diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index ef985444d..06d177e34 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -246,7 +246,7 @@ func TestSimulatedBackend_NonceAt(t *testing.T) { } // create a signed transaction to send - tx := types.NewTransaction(nonce, testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil) + tx := types.NewTransaction(nonce, testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil, types.SighashEIP155) signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey) if err != nil { t.Errorf("could not sign tx: %v", err) @@ -281,7 +281,7 @@ func TestSimulatedBackend_SendTransaction(t *testing.T) { bgCtx := context.Background() // create a signed transaction to send - tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil) + tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil, types.SighashEIP155) signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey) if err != nil { t.Errorf("could not sign tx: %v", err) @@ -316,7 +316,7 @@ func TestSimulatedBackend_TransactionByHash(t *testing.T) { bgCtx := context.Background() // create a signed transaction to send - tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil) + tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil, types.SighashEIP155) signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey) if err != nil { t.Errorf("could not sign tx: %v", err) @@ -481,7 +481,7 @@ func TestSimulatedBackend_TransactionCount(t *testing.T) { } // create a signed transaction to send - tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil) + tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil, types.SighashEIP155) signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey) if err != nil { t.Errorf("could not sign tx: %v", err) @@ -540,7 +540,7 @@ func TestSimulatedBackend_TransactionInBlock(t *testing.T) { } // create a signed transaction to send - tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil) + tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil, types.SighashEIP155) signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey) if err != nil { t.Errorf("could not sign tx: %v", err) @@ -599,7 +599,7 @@ func TestSimulatedBackend_PendingNonceAt(t *testing.T) { } // create a signed transaction to send - tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil) + tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil, types.SighashEIP155) signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey) if err != nil { t.Errorf("could not sign tx: %v", err) @@ -622,7 +622,7 @@ func TestSimulatedBackend_PendingNonceAt(t *testing.T) { } // make a new transaction with a nonce of 1 - tx = types.NewTransaction(uint64(1), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil) + tx = types.NewTransaction(uint64(1), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil, types.SighashEIP155) signedTx, err = types.SignTx(tx, types.HomesteadSigner{}, testKey) if err != nil { t.Errorf("could not sign tx: %v", err) @@ -655,7 +655,7 @@ func TestSimulatedBackend_TransactionReceipt(t *testing.T) { bgCtx := context.Background() // create a signed transaction to send - tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil) + tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil, nil, nil, types.SighashEIP155) signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey) if err != nil { t.Errorf("could not sign tx: %v", err) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index ac7cd120e..f01321cfc 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -229,7 +229,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i if contract == nil { rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input, nil, nil) } else { - rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input, nil, nil) + rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input, nil, nil, types.SighashEIP155) } if opts.Signer == nil { return nil, errors.New("no signer to authorize the transaction with") diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index c8c849f3f..de5fd3980 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -490,7 +490,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { amount = new(big.Int).Mul(amount, new(big.Int).Exp(big.NewInt(5), big.NewInt(int64(msg.Tier)), nil)) amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil)) - tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil, nil, nil) + tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil, nil, nil, types.SighashEIP155) signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID) if err != nil { f.lock.Unlock() diff --git a/common/varbytes.go b/common/varbytes.go new file mode 100644 index 000000000..602790f3e --- /dev/null +++ b/common/varbytes.go @@ -0,0 +1,383 @@ +// Copyright (c) 2013-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package common + +import ( + "encoding/binary" + "fmt" + "io" + "math" +) + +const ( + // MaxVarIntPayload is the maximum payload size for a variable length integer. + MaxVarIntPayload = 9 + + // binaryFreeListMaxItems is the number of buffers to keep in the free + // list to use for binary serialization and deserialization. + binaryFreeListMaxItems = 1024 +) + +var ( + // littleEndian is a convenience variable since binary.LittleEndian is + // quite long. + littleEndian = binary.LittleEndian +) + +// binaryFreeList defines a concurrent safe free list of byte slices (up to the +// maximum number defined by the binaryFreeListMaxItems constant) that have a +// cap of 8 (thus it supports up to a uint64). It is used to provide temporary +// buffers for serializing and deserializing primitive numbers to and from their +// binary encoding in order to greatly reduce the number of allocations +// required. +// +// For convenience, functions are provided for each of the primitive unsigned +// integers that automatically obtain a buffer from the free list, perform the +// necessary binary conversion, read from or write to the given io.Reader or +// io.Writer, and return the buffer to the free list. +type binaryFreeList chan []byte + +// Borrow returns a byte slice from the free list with a length of 8. A new +// buffer is allocated if there are not any available on the free list. +func (l binaryFreeList) Borrow() []byte { + var buf []byte + select { + case buf = <-l: + default: + buf = make([]byte, 8) + } + return buf[:8] +} + +// Return puts the provided byte slice back on the free list. The buffer MUST +// have been obtained via the Borrow function and therefore have a cap of 8. +func (l binaryFreeList) Return(buf []byte) { + select { + case l <- buf: + default: + // Let it go to the garbage collector. + } +} + +// Uint8 reads a single byte from the provided reader using a buffer from the +// free list and returns it as a uint8. +func (l binaryFreeList) Uint8(r io.Reader) (uint8, error) { + buf := l.Borrow()[:1] + if _, err := io.ReadFull(r, buf); err != nil { + l.Return(buf) + return 0, err + } + rv := buf[0] + l.Return(buf) + return rv, nil +} + +// Uint16 reads two bytes from the provided reader using a buffer from the +// free list, converts it to a number using the provided byte order, and returns +// the resulting uint16. +func (l binaryFreeList) Uint16(r io.Reader, byteOrder binary.ByteOrder) (uint16, error) { + buf := l.Borrow()[:2] + if _, err := io.ReadFull(r, buf); err != nil { + l.Return(buf) + return 0, err + } + rv := byteOrder.Uint16(buf) + l.Return(buf) + return rv, nil +} + +// Uint32 reads four bytes from the provided reader using a buffer from the +// free list, converts it to a number using the provided byte order, and returns +// the resulting uint32. +func (l binaryFreeList) Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) { + buf := l.Borrow()[:4] + if _, err := io.ReadFull(r, buf); err != nil { + l.Return(buf) + return 0, err + } + rv := byteOrder.Uint32(buf) + l.Return(buf) + return rv, nil +} + +// Uint64 reads eight bytes from the provided reader using a buffer from the +// free list, converts it to a number using the provided byte order, and returns +// the resulting uint64. +func (l binaryFreeList) Uint64(r io.Reader, byteOrder binary.ByteOrder) (uint64, error) { + buf := l.Borrow()[:8] + if _, err := io.ReadFull(r, buf); err != nil { + l.Return(buf) + return 0, err + } + rv := byteOrder.Uint64(buf) + l.Return(buf) + return rv, nil +} + +// PutUint8 copies the provided uint8 into a buffer from the free list and +// writes the resulting byte to the given writer. +func (l binaryFreeList) PutUint8(w io.Writer, val uint8) error { + buf := l.Borrow()[:1] + buf[0] = val + _, err := w.Write(buf) + l.Return(buf) + return err +} + +// PutUint16 serializes the provided uint16 using the given byte order into a +// buffer from the free list and writes the resulting two bytes to the given +// writer. +func (l binaryFreeList) PutUint16(w io.Writer, byteOrder binary.ByteOrder, val uint16) error { + buf := l.Borrow()[:2] + byteOrder.PutUint16(buf, val) + _, err := w.Write(buf) + l.Return(buf) + return err +} + +// PutUint32 serializes the provided uint32 using the given byte order into a +// buffer from the free list and writes the resulting four bytes to the given +// writer. +func (l binaryFreeList) PutUint32(w io.Writer, byteOrder binary.ByteOrder, val uint32) error { + buf := l.Borrow()[:4] + byteOrder.PutUint32(buf, val) + _, err := w.Write(buf) + l.Return(buf) + return err +} + +// PutUint64 serializes the provided uint64 using the given byte order into a +// buffer from the free list and writes the resulting eight bytes to the given +// writer. +func (l binaryFreeList) PutUint64(w io.Writer, byteOrder binary.ByteOrder, val uint64) error { + buf := l.Borrow()[:8] + byteOrder.PutUint64(buf, val) + _, err := w.Write(buf) + l.Return(buf) + return err +} + +// binarySerializer provides a free list of buffers to use for serializing and +// deserializing primitive integer values to and from io.Readers and io.Writers. +var binarySerializer binaryFreeList = make(chan []byte, binaryFreeListMaxItems) + +// errNonCanonicalVarInt is the common format string used for non-canonically +// encoded variable length integer errors. +var errNonCanonicalVarInt = "non-canonical varint %x - discriminant %x must " + + "encode a value greater than %x" + +// ReadVarInt reads a variable length integer from r and returns it as a uint64. +func ReadVarInt(r io.Reader, pver uint32) (uint64, error) { + discriminant, err := binarySerializer.Uint8(r) + if err != nil { + return 0, err + } + + var rv uint64 + switch discriminant { + case 0xff: + sv, err := binarySerializer.Uint64(r, littleEndian) + if err != nil { + return 0, err + } + rv = sv + + // The encoding is not canonical if the value could have been + // encoded using fewer bytes. + min := uint64(0x100000000) + if rv < min { + return 0, messageError("ReadVarInt", fmt.Sprintf( + errNonCanonicalVarInt, rv, discriminant, min)) + } + + case 0xfe: + sv, err := binarySerializer.Uint32(r, littleEndian) + if err != nil { + return 0, err + } + rv = uint64(sv) + + // The encoding is not canonical if the value could have been + // encoded using fewer bytes. + min := uint64(0x10000) + if rv < min { + return 0, messageError("ReadVarInt", fmt.Sprintf( + errNonCanonicalVarInt, rv, discriminant, min)) + } + + case 0xfd: + sv, err := binarySerializer.Uint16(r, littleEndian) + if err != nil { + return 0, err + } + rv = uint64(sv) + + // The encoding is not canonical if the value could have been + // encoded using fewer bytes. + min := uint64(0xfd) + if rv < min { + return 0, messageError("ReadVarInt", fmt.Sprintf( + errNonCanonicalVarInt, rv, discriminant, min)) + } + + default: + rv = uint64(discriminant) + } + + return rv, nil +} + +// WriteVarInt serializes val to w using a variable number of bytes depending +// on its value. +func WriteVarInt(w io.Writer, pver uint32, val uint64) error { + if val < 0xfd { + return binarySerializer.PutUint8(w, uint8(val)) + } + + if val <= math.MaxUint16 { + err := binarySerializer.PutUint8(w, 0xfd) + if err != nil { + return err + } + return binarySerializer.PutUint16(w, littleEndian, uint16(val)) + } + + if val <= math.MaxUint32 { + err := binarySerializer.PutUint8(w, 0xfe) + if err != nil { + return err + } + return binarySerializer.PutUint32(w, littleEndian, uint32(val)) + } + + err := binarySerializer.PutUint8(w, 0xff) + if err != nil { + return err + } + return binarySerializer.PutUint64(w, littleEndian, val) +} + +// VarIntSerializeSize returns the number of bytes it would take to serialize +// val as a variable length integer. +func VarIntSerializeSize(val uint64) int { + // The value is small enough to be represented by itself, so it's + // just 1 byte. + if val < 0xfd { + return 1 + } + + // Discriminant 1 byte plus 2 bytes for the uint16. + if val <= math.MaxUint16 { + return 3 + } + + // Discriminant 1 byte plus 4 bytes for the uint32. + if val <= math.MaxUint32 { + return 5 + } + + // Discriminant 1 byte plus 8 bytes for the uint64. + return 9 +} + +// ReadVarString reads a variable length string from r and returns it as a Go +// string. A variable length string is encoded as a variable length integer +// containing the length of the string followed by the bytes that represent the +// string itself. +func ReadVarString(r io.Reader, pver uint32) (string, error) { + count, err := ReadVarInt(r, pver) + if err != nil { + return "", err + } + + buf := make([]byte, count) + _, err = io.ReadFull(r, buf) + if err != nil { + return "", err + } + return string(buf), nil +} + +// WriteVarString serializes str to w as a variable length integer containing +// the length of the string followed by the bytes that represent the string +// itself. +func WriteVarString(w io.Writer, pver uint32, str string) error { + err := WriteVarInt(w, pver, uint64(len(str))) + if err != nil { + return err + } + _, err = w.Write([]byte(str)) + return err +} + +// ReadVarBytes reads a variable length byte array. A byte array is encoded +// as a varInt containing the length of the array followed by the bytes +// themselves. An error is returned if the length is greater than the +// passed maxAllowed parameter which helps protect against memory exhaustion +// attacks and forced panics through malformed messages. The fieldName +// parameter is only used for the error message so it provides more context in +// the error. +func ReadVarBytes(r io.Reader, pver uint32, maxAllowed uint32, + fieldName string) ([]byte, error) { + + count, err := ReadVarInt(r, pver) + if err != nil { + return nil, err + } + + // Prevent byte array larger than the max message size. It would + // be possible to cause memory exhaustion and panics without a sane + // upper bound on this count. + if count > uint64(maxAllowed) { + str := fmt.Sprintf("%s is larger than the max allowed size "+ + "[count %d, max %d]", fieldName, count, maxAllowed) + return nil, messageError("ReadVarBytes", str) + } + + b := make([]byte, count) + _, err = io.ReadFull(r, b) + if err != nil { + return nil, err + } + return b, nil +} + +// WriteVarBytes serializes a variable length byte array to w as a varInt +// containing the number of bytes, followed by the bytes themselves. +func WriteVarBytes(w io.Writer, pver uint32, bytes []byte) error { + slen := uint64(len(bytes)) + err := WriteVarInt(w, pver, slen) + if err != nil { + return err + } + + _, err = w.Write(bytes) + return err +} + +// MessageError describes an issue with a message. +// An example of some potential issues are messages from the wrong bitcoin +// network, invalid commands, mismatched checksums, and exceeding max payloads. +// +// This provides a mechanism for the caller to type assert the error to +// differentiate between general io errors such as io.EOF and issues that +// resulted from malformed messages. +type MessageError struct { + Func string // Function name + Description string // Human readable description of the issue +} + +// Error satisfies the error interface and prints human-readable errors. +func (e *MessageError) Error() string { + if e.Func != "" { + return fmt.Sprintf("%v: %v", e.Func, e.Description) + } + return e.Description +} + +// messageError creates an error for the given function and description. +func messageError(f string, desc string) *MessageError { + return &MessageError{Func: f, Description: desc} +} diff --git a/consensus/clique/clique_test.go b/consensus/clique/clique_test.go index 5da135444..8a6f682b5 100644 --- a/consensus/clique/clique_test.go +++ b/consensus/clique/clique_test.go @@ -65,7 +65,7 @@ func TestReimportMirroredState(t *testing.T) { // We want to simulate an empty middle block, having the same state as the // first one. The last is needs a state change again to force a reorg. if i != 1 { - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr), common.Address{0x00}, new(big.Int), params.TxGas, nil, nil, nil, nil), signer, key) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr), common.Address{0x00}, new(big.Int), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, key) if err != nil { panic(err) } diff --git a/core/bench_test.go b/core/bench_test.go index b0e6a1796..0dec9e904 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -86,7 +86,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { toaddr := common.Address{} data := make([]byte, nbytes) gas, _ := IntrinsicGas(data, false, false, false) - tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data, nil, nil), types.HomesteadSigner{}, benchRootKey) + tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data, nil, nil, types.SighashEIP155), types.HomesteadSigner{}, benchRootKey) gen.AddTx(tx) } } @@ -119,7 +119,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) { break } to := (from + 1) % naccounts - tx := types.NewTransaction(gen.TxNonce(ringAddrs[from]), ringAddrs[to], benchRootFunds, params.TxGas, nil, nil, nil, nil) + tx := types.NewTransaction(gen.TxNonce(ringAddrs[from]), ringAddrs[to], benchRootFunds, params.TxGas, nil, nil, nil, nil, types.SighashEIP155) tx, _ = types.SignTx(tx, types.HomesteadSigner{}, ringKeys[from]) gen.AddTx(tx) from = to diff --git a/core/blockchain.go b/core/blockchain.go index f49dc47d3..5daaa371f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1221,6 +1221,9 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ rawdb.WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()) rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receiptChain[i]) rawdb.WriteTxLookupEntries(batch, block) + for _, tx := range block.Transactions() { + rawdb.WriteTransactionMeta(batch, tx.Hash(), tx.GetMeta()) + } // Write everything belongs to the blocks into the database. So that // we can ensure all components of body is completed(body, receipts, @@ -1343,6 +1346,9 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. blockBatch := bc.db.NewBatch() rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd) rawdb.WriteBlock(blockBatch, block) + for _, tx := range block.Transactions() { + rawdb.WriteTransactionMeta(blockBatch, tx.Hash(), tx.GetMeta()) + } rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts) rawdb.WritePreimages(blockBatch, state.Preimages()) if err := blockBatch.Write(); err != nil { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index cfb05cb88..ef0bb5f98 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -607,7 +607,7 @@ func TestFastVsFullChains(t *testing.T) { // If the block number is multiple of 3, send a few bonus transactions to the miner if i%3 == 2 { for j := 0; j < i%4+1; j++ { - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, key) if err != nil { panic(err) } @@ -840,8 +840,8 @@ func TestChainTxReorgs(t *testing.T) { // Create two transactions shared between the chains: // - postponed: transaction included at a later block in the forked chain // - swapped: transaction included at the same block number in the forked chain - postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key1) - swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key1) + postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, key1) + swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, key1) // Create two transactions that will be dropped by the forked chain: // - pastDrop: transaction dropped retroactively from a past block @@ -857,13 +857,13 @@ func TestChainTxReorgs(t *testing.T) { chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) { switch i { case 0: - pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key2) + pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, key2) gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork case 2: - freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key2) + freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, key2) gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point gen.AddTx(swapped) // This transaction will be swapped out at the exact height @@ -882,18 +882,18 @@ func TestChainTxReorgs(t *testing.T) { chain, _ = GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) { switch i { case 0: - pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key3) + pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, key3) gen.AddTx(pastAdd) // This transaction needs to be injected during reorg case 2: gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain - freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key3) + freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, key3) gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time case 3: - futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key3) + futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, key3) gen.AddTx(futureAdd) // This transaction will be added after a full reorg } }) @@ -1340,7 +1340,7 @@ func TestEIP155Transition(t *testing.T) { tx *types.Transaction err error basicTx = func(signer types.Signer) (*types.Transaction, error) { - return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil, nil, nil), signer, key) + return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil, nil, nil, types.SighashEIP155), signer, key) } ) switch i { @@ -1403,7 +1403,7 @@ func TestEIP155Transition(t *testing.T) { tx *types.Transaction err error basicTx = func(signer types.Signer) (*types.Transaction, error) { - return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil, nil, nil), signer, key) + return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil, nil, nil, types.SighashEIP155), signer, key) } ) if i == 0 { @@ -1453,11 +1453,11 @@ func TestEIP161AccountRemoval(t *testing.T) { ) switch i { case 0: - tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil, nil, nil), signer, key) + tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil, nil, nil, types.SighashEIP155), signer, key) case 1: - tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil, nil, nil), signer, key) + tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil, nil, nil, types.SighashEIP155), signer, key) case 2: - tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil, nil, nil), signer, key) + tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil, nil, nil, types.SighashEIP155), signer, key) } if err != nil { t.Fatal(err) @@ -2166,7 +2166,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in for txi := 0; txi < numTxs; txi++ { uniq := uint64(i*numTxs + txi) recipient := recipientFn(uniq) - tx, err := types.SignTx(types.NewTransaction(uniq, recipient, big.NewInt(1), params.TxGas, big.NewInt(1), nil, nil, nil), signer, testBankKey) + tx, err := types.SignTx(types.NewTransaction(uniq, recipient, big.NewInt(1), params.TxGas, big.NewInt(1), nil, nil, nil, types.SighashEIP155), signer, testBankKey) if err != nil { b.Error(err) } @@ -2346,10 +2346,10 @@ func TestDeleteCreateRevert(t *testing.T) { blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) // One transaction to AAAA - tx, _ := types.SignTx(types.NewTransaction(0, aa, big.NewInt(0), 50000, big.NewInt(1), nil, nil, nil), types.HomesteadSigner{}, key) + tx, _ := types.SignTx(types.NewTransaction(0, aa, big.NewInt(0), 50000, big.NewInt(1), nil, nil, nil, types.SighashEIP155), types.HomesteadSigner{}, key) b.AddTx(tx) // One transaction to BBBB - tx, _ = types.SignTx(types.NewTransaction(1, bb, big.NewInt(0), 100000, big.NewInt(1), nil, nil, nil), types.HomesteadSigner{}, key) + tx, _ = types.SignTx(types.NewTransaction(1, bb, big.NewInt(0), 100000, big.NewInt(1), nil, nil, nil, types.SighashEIP155), types.HomesteadSigner{}, key) b.AddTx(tx) }) // Import the canonical chain diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 4d064a339..bd8871760 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -338,6 +338,53 @@ func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { } } +// ReadTransactionMeta returns the transaction metadata associated with a +// transaction hash. +func ReadTransactionMeta(db ethdb.Reader, hash common.Hash) *types.TransactionMeta { + data := ReadTransactionMetaRaw(db, hash) + if len(data) == 0 { + return nil + } + + meta, err := types.TxMetaDecode(data) + if err != nil { + log.Error("Invalid raw tx meta ", "hash", hash, "err", err) + return nil + } + + return meta +} + +// ReadTransactionMetaRaw returns the raw transaction metadata associated with a +// transaction hash. +func ReadTransactionMetaRaw(db ethdb.Reader, hash common.Hash) []byte { + data, _ := db.Get(txMetaKey(hash)) + if len(data) > 0 { + return data + } + return nil +} + +// WriteTransactionMeta writes the TransactionMeta to disk by hash. +func WriteTransactionMeta(db ethdb.KeyValueWriter, hash common.Hash, meta *types.TransactionMeta) { + data := types.TxMetaEncode(meta) + WriteTransactionMetaRaw(db, hash, data) +} + +// WriteTransactionMetaRaw writes the raw transaction metadata bytes to disk. +func WriteTransactionMetaRaw(db ethdb.KeyValueWriter, hash common.Hash, data []byte) { + if err := db.Put(txMetaKey(hash), data); err != nil { + log.Crit("Failed to store transaction meta", "err", err) + } +} + +// DeleteTransactionMeta removes the transaction metadata associated with a hash +func DeleteTransactionMeta(db ethdb.KeyValueWriter, hash common.Hash) { + if err := db.Delete(txMetaKey(hash)); err != nil { + log.Crit("Failed to delete transaction meta", "err", err) + } +} + // ReadTdRLP retrieves a block's total difficulty corresponding to the hash in RLP encoding. func ReadTdRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { // First try to look up the data in ancient database. Extra hash diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 0ffdae7e6..a769ed16c 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -26,6 +26,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" @@ -273,8 +274,8 @@ func TestBlockReceiptStorage(t *testing.T) { db := NewMemoryDatabase() // Create a live block since we need metadata to reconstruct the receipt - tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil, nil, nil) - tx2 := types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil, nil, nil) + tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil, nil, nil, types.SighashEIP155) + tx2 := types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil, nil, nil, types.SighashEIP155) body := &types.Body{Transactions: types.Transactions{tx1, tx2}} @@ -424,3 +425,49 @@ func TestAncientStorage(t *testing.T) { t.Fatalf("invalid td returned") } } + +func TestBlockMetaStorage(t *testing.T) { + db := NewMemoryDatabase() + + tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil, nil, nil, types.SighashEIP155) + + WriteTransactionMeta(db, tx1.Hash(), tx1.GetMeta()) + meta := ReadTransactionMeta(db, tx1.Hash()) + + if meta.L1MessageSender != nil { + t.Fatalf("Could not recover L1MessageSender") + } + if meta.L1RollupTxId != nil { + t.Fatalf("Could not recover L1RollupTxId") + } + + if meta.SignatureHashType != types.SighashEIP155 { + t.Fatalf("Could not recover sighash type") + } + + DeleteTransactionMeta(db, tx1.Hash()) + postDelete := ReadTransactionMeta(db, tx1.Hash()) + + if postDelete != nil { + t.Fatalf("Delete did not work") + } + + addr := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") + txid := hexutil.Uint64(777) + + tx2 := types.NewTransaction(2, common.HexToAddress("0x02"), big.NewInt(2), 2, big.NewInt(2), nil, &addr, &txid, types.SighashEthSign) + + WriteTransactionMeta(db, tx2.Hash(), tx2.GetMeta()) + meta2 := ReadTransactionMeta(db, tx2.Hash()) + + if !bytes.Equal(meta2.L1MessageSender.Bytes(), addr.Bytes()) { + t.Fatalf("Could not recover L1MessageSender") + } + + if *meta2.L1RollupTxId != txid { + t.Fatalf("Could not recover L1RollupTxId") + } + if meta2.SignatureHashType != types.SighashEthSign { + t.Fatalf("Could not recover sighash type") + } +} diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index 3116e04af..fee87ce78 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -86,6 +86,11 @@ func ReadTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, com } for txIndex, tx := range body.Transactions { if tx.Hash() == hash { + txMeta := ReadTransactionMeta(db, hash) + if txMeta != nil { + tx.SetTransactionMeta(txMeta) + } + return tx, blockHash, *blockNumber, uint64(txIndex) } } diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go index 969a341c6..9e3885329 100644 --- a/core/rawdb/accessors_indexes_test.go +++ b/core/rawdb/accessors_indexes_test.go @@ -74,9 +74,9 @@ func TestLookupStorage(t *testing.T) { l1RollupTxId1 := hexutil.Uint64(1) l1RollupTxId2 := hexutil.Uint64(2) - tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11}, &sender1, &l1RollupTxId1) - tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22}, &sender2, &l1RollupTxId2) - tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33}, nil, &l1RollupTxId1) + tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11}, &sender1, &l1RollupTxId1, types.SighashEIP155) + tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22}, &sender2, &l1RollupTxId2, types.SighashEIP155) + tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33}, nil, &l1RollupTxId1, types.SighashEIP155) txs := []*types.Transaction{tx1, tx2, tx3} block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil) diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index a44a2c99f..4e9caca1a 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -53,6 +53,9 @@ var ( txLookupPrefix = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits + // Optmism specific + txMetaPrefix = []byte("x") // txMetaPrefix + hash -> transaction metadata + preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage configPrefix = []byte("ethereum-config-") // config prefix for the db @@ -145,6 +148,11 @@ func txLookupKey(hash common.Hash) []byte { return append(txLookupPrefix, hash.Bytes()...) } +// txMetaKey = txMetaPrefix + hash +func txMetaKey(hash common.Hash) []byte { + return append(txMetaPrefix, hash.Bytes()...) +} + // bloomBitsKey = bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash func bloomBitsKey(bit uint, section uint64, hash common.Hash) []byte { key := append(append(bloomBitsPrefix, make([]byte, 10)...), hash.Bytes()...) diff --git a/core/tx_pool.go b/core/tx_pool.go index ae6962c5d..5672ddd8a 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -271,7 +271,7 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block config: config, chainconfig: chainconfig, chain: chain, - signer: types.NewEIP155Signer(chainconfig.ChainID), + signer: types.NewOVMSigner(chainconfig.ChainID), pending: make(map[common.Address]*txList), queue: make(map[common.Address]*txList), beats: make(map[common.Address]time.Time), diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index d34430477..a46b9dc71 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -73,7 +73,7 @@ func transaction(nonce uint64, gaslimit uint64, key *ecdsa.PrivateKey) *types.Tr } func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction { - tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, gasprice, nil, nil, nil), types.HomesteadSigner{}, key) + tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, gasprice, nil, nil, nil, types.SighashEIP155), types.HomesteadSigner{}, key) return tx } @@ -81,7 +81,7 @@ func pricedDataTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key data := make([]byte, bytes) rand.Read(data) - tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(0), gaslimit, gasprice, data, nil, nil), types.HomesteadSigner{}, key) + tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(0), gaslimit, gasprice, data, nil, nil, types.SighashEIP155), types.HomesteadSigner{}, key) return tx } @@ -329,7 +329,7 @@ func TestTransactionNegativeValue(t *testing.T) { pool, key := setupTxPool() defer pool.Stop() - tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil, nil, nil), types.HomesteadSigner{}, key) + tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil, nil, nil, types.SighashEIP155), types.HomesteadSigner{}, key) from, _ := deriveSender(tx) pool.currentState.AddBalance(from, big.NewInt(1)) if err := pool.AddRemote(tx); err != ErrNegativeValue { @@ -383,9 +383,9 @@ func TestTransactionDoubleNonce(t *testing.T) { resetState() signer := types.HomesteadSigner{} - tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 100000, big.NewInt(1), nil, nil, nil), signer, key) - tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(2), nil, nil, nil), signer, key) - tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(1), nil, nil, nil), signer, key) + tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 100000, big.NewInt(1), nil, nil, nil, types.SighashEIP155), signer, key) + tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(2), nil, nil, nil, types.SighashEIP155), signer, key) + tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(1), nil, nil, nil, types.SighashEIP155), signer, key) // Add the first two transaction, ensure higher priced stays only if replace, err := pool.add(tx1, false); err != nil || replace { diff --git a/core/types/block_test.go b/core/types/block_test.go index f861053b4..86c3afd3d 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -50,7 +50,7 @@ func TestBlockEncoding(t *testing.T) { check("Time", block.Time(), uint64(1426516743)) check("Size", block.Size(), common.StorageSize(len(blockEnc))) - tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil, nil, nil) + tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil, nil, nil, SighashEIP155) tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")) check("len(Transactions)", len(block.Transactions()), 1) check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash()) diff --git a/core/types/gen_tx_json.go b/core/types/gen_tx_json.go index 2e7360875..904f2c1d1 100644 --- a/core/types/gen_tx_json.go +++ b/core/types/gen_tx_json.go @@ -13,101 +13,111 @@ import ( var _ = (*txdataMarshaling)(nil) -// MarshalJSON marshals as JSON. -func (t txdata) MarshalJSON() ([]byte, error) { - type txdata struct { - AccountNonce hexutil.Uint64 `json:"nonce" gencodec:"required"` - Price *hexutil.Big `json:"gasPrice" gencodec:"required"` - GasLimit hexutil.Uint64 `json:"gas" gencodec:"required"` - Recipient *common.Address `json:"to" rlp:"nil"` - Amount *hexutil.Big `json:"value" gencodec:"required"` - Payload hexutil.Bytes `json:"input" gencodec:"required"` - V *hexutil.Big `json:"v" gencodec:"required"` - R *hexutil.Big `json:"r" gencodec:"required"` - S *hexutil.Big `json:"s" gencodec:"required"` - Hash *common.Hash `json:"hash" rlp:"-"` - L1RollupTxId *hexutil.Uint64 `json:"l1RollupTxId,omitempty" rlp:"nil,?"` - L1MessageSender *common.Address `json:"l1MessageSender,omitempty" rlp:"nil,?"` +// TransactionMarshalJSON marshals as JSON. +func TransactionMarshalJSON(t *Transaction) ([]byte, error) { + type txnjson struct { + AccountNonce hexutil.Uint64 `json:"nonce" gencodec:"required"` + Price *hexutil.Big `json:"gasPrice" gencodec:"required"` + GasLimit hexutil.Uint64 `json:"gas" gencodec:"required"` + Recipient *common.Address `json:"to" rlp:"nil"` + Amount *hexutil.Big `json:"value" gencodec:"required"` + Payload hexutil.Bytes `json:"input" gencodec:"required"` + V *hexutil.Big `json:"v" gencodec:"required"` + R *hexutil.Big `json:"r" gencodec:"required"` + S *hexutil.Big `json:"s" gencodec:"required"` + Hash *common.Hash `json:"hash" rlp:"-"` + L1RollupTxId *hexutil.Uint64 `json:"l1RollupTxId,omitempty" rlp:"nil,?"` + L1MessageSender *common.Address `json:"l1MessageSender,omitempty" rlp:"nil,?"` + SignatureHashType SignatureHashType `json:"signatureHashType,omitempty" rlp:"nil,?"` } - var enc txdata - enc.AccountNonce = hexutil.Uint64(t.AccountNonce) - enc.Price = (*hexutil.Big)(t.Price) - enc.GasLimit = hexutil.Uint64(t.GasLimit) - enc.Recipient = t.Recipient - enc.L1MessageSender = t.L1MessageSender - enc.L1RollupTxId = t.L1RollupTxId - enc.Amount = (*hexutil.Big)(t.Amount) - enc.Payload = t.Payload - enc.V = (*hexutil.Big)(t.V) - enc.R = (*hexutil.Big)(t.R) - enc.S = (*hexutil.Big)(t.S) - enc.Hash = t.Hash + + var enc txnjson + enc.AccountNonce = hexutil.Uint64(t.data.AccountNonce) + enc.Price = (*hexutil.Big)(t.data.Price) + enc.GasLimit = hexutil.Uint64(t.data.GasLimit) + enc.Recipient = t.data.Recipient + enc.L1MessageSender = t.meta.L1MessageSender + enc.L1RollupTxId = t.meta.L1RollupTxId + enc.SignatureHashType = t.meta.SignatureHashType + enc.Amount = (*hexutil.Big)(t.data.Amount) + enc.Payload = t.data.Payload + enc.V = (*hexutil.Big)(t.data.V) + enc.R = (*hexutil.Big)(t.data.R) + enc.S = (*hexutil.Big)(t.data.S) + hash := t.Hash() + enc.Hash = &hash return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. -func (t *txdata) UnmarshalJSON(input []byte) error { - type txdata struct { - AccountNonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` - Price *hexutil.Big `json:"gasPrice" gencodec:"required"` - GasLimit *hexutil.Uint64 `json:"gas" gencodec:"required"` - Recipient *common.Address `json:"to" rlp:"nil"` - Amount *hexutil.Big `json:"value" gencodec:"required"` - Payload *hexutil.Bytes `json:"input" gencodec:"required"` - V *hexutil.Big `json:"v" gencodec:"required"` - R *hexutil.Big `json:"r" gencodec:"required"` - S *hexutil.Big `json:"s" gencodec:"required"` - Hash *common.Hash `json:"hash" rlp:"-"` - L1RollupTxId *hexutil.Uint64 `json:"l1RollupTxId,omitempty" rlp:"nil,?"` - L1MessageSender *common.Address `json:"l1MessageSender,omitempty" rlp:"nil,?"` +func TransactionUnmarshalJSON(input []byte) (*Transaction, error) { + type txnjson struct { + AccountNonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` + Price *hexutil.Big `json:"gasPrice" gencodec:"required"` + GasLimit *hexutil.Uint64 `json:"gas" gencodec:"required"` + Recipient *common.Address `json:"to" rlp:"nil"` + Amount *hexutil.Big `json:"value" gencodec:"required"` + Payload *hexutil.Bytes `json:"input" gencodec:"required"` + V *hexutil.Big `json:"v" gencodec:"required"` + R *hexutil.Big `json:"r" gencodec:"required"` + S *hexutil.Big `json:"s" gencodec:"required"` + Hash *common.Hash `json:"hash" rlp:"-"` + L1RollupTxId *hexutil.Uint64 `json:"l1RollupTxId,omitempty"` + L1MessageSender *common.Address `json:"l1MessageSender,omitempty"` + SignatureHashType SignatureHashType `json:"signatureHashType"` } - var dec txdata + + var t Transaction + var dec txnjson if err := json.Unmarshal(input, &dec); err != nil { - return err + return &Transaction{}, err } if dec.AccountNonce == nil { - return errors.New("missing required field 'nonce' for txdata") + return &Transaction{}, errors.New("missing required field 'nonce' for txdata") } - t.AccountNonce = uint64(*dec.AccountNonce) + t.data.AccountNonce = uint64(*dec.AccountNonce) if dec.Price == nil { - return errors.New("missing required field 'gasPrice' for txdata") + return &Transaction{}, errors.New("missing required field 'gasPrice' for txdata") } - t.Price = (*big.Int)(dec.Price) + t.data.Price = (*big.Int)(dec.Price) if dec.GasLimit == nil { - return errors.New("missing required field 'gas' for txdata") + return &Transaction{}, errors.New("missing required field 'gas' for txdata") } - t.GasLimit = uint64(*dec.GasLimit) + t.data.GasLimit = uint64(*dec.GasLimit) if dec.Recipient != nil { - t.Recipient = dec.Recipient + t.data.Recipient = dec.Recipient } if dec.L1MessageSender != nil { - t.L1MessageSender = dec.L1MessageSender + t.meta.L1MessageSender = dec.L1MessageSender } if dec.L1RollupTxId != nil { - t.L1RollupTxId = dec.L1RollupTxId + t.meta.L1RollupTxId = dec.L1RollupTxId } + + t.meta.SignatureHashType = dec.SignatureHashType + if dec.Amount == nil { - return errors.New("missing required field 'value' for txdata") + return &Transaction{}, errors.New("missing required field 'value' for txdata") } - t.Amount = (*big.Int)(dec.Amount) + t.data.Amount = (*big.Int)(dec.Amount) if dec.Payload == nil { - return errors.New("missing required field 'input' for txdata") + return &Transaction{}, errors.New("missing required field 'input' for txdata") } - t.Payload = *dec.Payload + t.data.Payload = *dec.Payload if dec.V == nil { - return errors.New("missing required field 'v' for txdata") + return &Transaction{}, errors.New("missing required field 'v' for txdata") } - t.V = (*big.Int)(dec.V) + t.data.V = (*big.Int)(dec.V) if dec.R == nil { - return errors.New("missing required field 'r' for txdata") + return &Transaction{}, errors.New("missing required field 'r' for txdata") } - t.R = (*big.Int)(dec.R) + t.data.R = (*big.Int)(dec.R) if dec.S == nil { - return errors.New("missing required field 's' for txdata") + return &Transaction{}, errors.New("missing required field 's' for txdata") } - t.S = (*big.Int)(dec.S) + t.data.S = (*big.Int)(dec.S) if dec.Hash != nil { - t.Hash = dec.Hash + t.data.Hash = dec.Hash } - return nil + return &t, nil } diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index 3ff36d0c5..5f00c74be 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -48,7 +48,7 @@ func TestLegacyReceiptDecoding(t *testing.T) { }, } - tx := NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil, nil, nil) + tx := NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil, nil, nil, SighashEIP155) receipt := &Receipt{ Status: ReceiptStatusFailed, CumulativeGasUsed: 1, @@ -156,7 +156,7 @@ func TestDeriveFields(t *testing.T) { // Create a few transactions to have receipts for txs := Transactions{ NewContractCreation(1, big.NewInt(1), 1, big.NewInt(1), nil, nil, nil), - NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil, nil, nil), + NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil, nil, nil, SighashEIP155), } // Create the corresponding receipts receipts := Receipts{ diff --git a/core/types/transaction.go b/core/types/transaction.go index 9a9181be0..94eade251 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -36,8 +36,16 @@ var ( ErrInvalidSig = errors.New("invalid transaction v, r, s values") ) +type SignatureHashType uint8 + +const ( + SighashEIP155 SignatureHashType = 0 + SighashEthSign SignatureHashType = 1 +) + type Transaction struct { data txdata + meta TransactionMeta // caches hash atomic.Value size atomic.Value @@ -58,9 +66,7 @@ type txdata struct { S *big.Int `json:"s" gencodec:"required"` // This is only used when marshaling to JSON. - Hash *common.Hash `json:"hash" rlp:"-"` - L1RollupTxId *hexutil.Uint64 `json:"l1RollupTxId,omitempty" rlp:"nil,?"` - L1MessageSender *common.Address `json:"l1MessageSender,omitempty" rlp:"nil,?"` + Hash *common.Hash `json:"hash" rlp:"-"` } type txdataMarshaling struct { @@ -74,30 +80,35 @@ type txdataMarshaling struct { S *hexutil.Big } -func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, l1MessageSender *common.Address, l1RollupTxId *hexutil.Uint64) *Transaction { - return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data, l1MessageSender, l1RollupTxId) +func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, l1MessageSender *common.Address, l1RollupTxId *hexutil.Uint64, sighashType SignatureHashType) *Transaction { + return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data, l1MessageSender, l1RollupTxId, sighashType) } func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, l1MessageSender *common.Address, l1RollupTxId *hexutil.Uint64) *Transaction { - return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data, l1MessageSender, l1RollupTxId) + return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data, l1MessageSender, l1RollupTxId, SighashEIP155) } -func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, l1MessageSender *common.Address, l1RollupTxId *hexutil.Uint64) *Transaction { +func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, l1MessageSender *common.Address, l1RollupTxId *hexutil.Uint64, sighashType SignatureHashType) *Transaction { if len(data) > 0 { data = common.CopyBytes(data) } + + meta := TransactionMeta{ + L1RollupTxId: l1RollupTxId, + L1MessageSender: l1MessageSender, + SignatureHashType: sighashType, + } + d := txdata{ - AccountNonce: nonce, - Recipient: to, - L1MessageSender: l1MessageSender, - L1RollupTxId: l1RollupTxId, - Payload: data, - Amount: new(big.Int), - GasLimit: gasLimit, - Price: new(big.Int), - V: new(big.Int), - R: new(big.Int), - S: new(big.Int), + AccountNonce: nonce, + Recipient: to, + Payload: data, + Amount: new(big.Int), + GasLimit: gasLimit, + Price: new(big.Int), + V: new(big.Int), + R: new(big.Int), + S: new(big.Int), } if amount != nil { d.Amount.Set(amount) @@ -106,7 +117,21 @@ func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit d.Price.Set(gasPrice) } - return &Transaction{data: d} + return &Transaction{data: d, meta: meta} +} + +func (t *Transaction) SetTransactionMeta(meta *TransactionMeta) { + if meta == nil { + return + } + t.meta = *meta +} + +func (t *Transaction) GetMeta() *TransactionMeta { + if &t.meta == nil { + return &TransactionMeta{} + } + return &t.meta } // Appends the provided 64-bit nonce to this Transaction's calldata as the last 4 bytes @@ -169,43 +194,49 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error { // MarshalJSON encodes the web3 RPC transaction format. func (tx *Transaction) MarshalJSON() ([]byte, error) { - hash := tx.Hash() - data := tx.data - data.Hash = &hash - return data.MarshalJSON() + return TransactionMarshalJSON(tx) } // UnmarshalJSON decodes the web3 RPC transaction format. func (tx *Transaction) UnmarshalJSON(input []byte) error { - var dec txdata - if err := dec.UnmarshalJSON(input); err != nil { + dec, err := TransactionUnmarshalJSON(input) + if err != nil { return err } - withSignature := dec.V.Sign() != 0 || dec.R.Sign() != 0 || dec.S.Sign() != 0 + withSignature := dec.data.V.Sign() != 0 || dec.data.R.Sign() != 0 || dec.data.S.Sign() != 0 if withSignature { var V byte - if isProtectedV(dec.V) { - chainID := deriveChainId(dec.V).Uint64() - V = byte(dec.V.Uint64() - 35 - 2*chainID) + if isProtectedV(dec.data.V) { + chainID := deriveChainId(dec.data.V).Uint64() + V = byte(dec.data.V.Uint64() - 35 - 2*chainID) } else { - V = byte(dec.V.Uint64() - 27) + V = byte(dec.data.V.Uint64() - 27) } - if !crypto.ValidateSignatureValues(V, dec.R, dec.S, false) { + if !crypto.ValidateSignatureValues(V, dec.data.R, dec.data.S, false) { return ErrInvalidSig } } - *tx = Transaction{data: dec} + *tx = *dec return nil } -func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) } -func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit } -func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) } -func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) } -func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce } -func (tx *Transaction) CheckNonce() bool { return true } +func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) } +func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit } +func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) } +func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) } +func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce } +func (tx *Transaction) CheckNonce() bool { return true } +func (tx *Transaction) SignatureHashType() SignatureHashType { return tx.meta.SignatureHashType } + +func (tx *Transaction) SetSignatureHashType(sighashType SignatureHashType) { + tx.meta.SignatureHashType = sighashType +} + +func (tx *Transaction) IsEthSignSighash() bool { + return tx.SignatureHashType() == SighashEthSign +} // To returns the recipient address of the transaction. // It returns nil if the transaction is a contract creation. @@ -220,20 +251,20 @@ func (tx *Transaction) To() *common.Address { // L1MessageSender returns the L1 message sender address of the transaction if one exists. // It returns nil if this transaction was not from an L1 contract. func (tx *Transaction) L1MessageSender() *common.Address { - if tx.data.L1MessageSender == nil { + if tx.meta.L1MessageSender == nil { return nil } - l1MessageSender := *tx.data.L1MessageSender + l1MessageSender := *tx.meta.L1MessageSender return &l1MessageSender } // L1RollupTxId returns the L1 Rollup Tx Id of the transaction if one exists. // It returns nil if this transaction was not generated from a transaction received on L1. func (tx *Transaction) L1RollupTxId() *hexutil.Uint64 { - if tx.data.L1RollupTxId == nil { + if tx.meta.L1RollupTxId == nil { return nil } - l1RolupTxId := *tx.data.L1RollupTxId + l1RolupTxId := *tx.meta.L1RollupTxId return &l1RolupTxId } @@ -244,20 +275,7 @@ func (tx *Transaction) Hash() common.Hash { return hash.(common.Hash) } - var sender *common.Address - var l1RollupTxId *hexutil.Uint64 - if tx != nil { - sender = tx.data.L1MessageSender - tx.data.L1MessageSender = nil - l1RollupTxId = tx.data.L1RollupTxId - tx.data.L1RollupTxId = nil - } v := rlpHash(tx) - - if tx != nil { - tx.data.L1MessageSender = sender - tx.data.L1RollupTxId = l1RollupTxId - } tx.hash.Store(v) return v } @@ -281,15 +299,16 @@ func (tx *Transaction) Size() common.StorageSize { // XXX Rename message to something less arbitrary? func (tx *Transaction) AsMessage(s Signer) (Message, error) { msg := Message{ - nonce: tx.data.AccountNonce, - gasLimit: tx.data.GasLimit, - gasPrice: new(big.Int).Set(tx.data.Price), - to: tx.data.Recipient, - l1MessageSender: tx.data.L1MessageSender, - l1RollupTxId: tx.data.L1RollupTxId, - amount: tx.data.Amount, - data: tx.data.Payload, - checkNonce: true, + nonce: tx.data.AccountNonce, + gasLimit: tx.data.GasLimit, + gasPrice: new(big.Int).Set(tx.data.Price), + to: tx.data.Recipient, + l1MessageSender: tx.meta.L1MessageSender, + l1RollupTxId: tx.meta.L1RollupTxId, + signatureHashType: tx.meta.SignatureHashType, + amount: tx.data.Amount, + data: tx.data.Payload, + checkNonce: true, } var err error @@ -304,7 +323,7 @@ func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, e if err != nil { return nil, err } - cpy := &Transaction{data: tx.data} + cpy := &Transaction{data: tx.data, meta: tx.meta} cpy.data.R, cpy.data.S, cpy.data.V = r, s, v return cpy, nil } @@ -402,12 +421,15 @@ func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transa // Initialize a price based heap with the head transactions heads := make(TxByPrice, 0, len(txs)) for from, accTxs := range txs { - heads = append(heads, accTxs[0]) - // Ensure the sender address is from the signer - acc, _ := Sender(signer, accTxs[0]) - txs[acc] = accTxs[1:] - if from != acc { - delete(txs, from) + // This prevents a panic, not ideal. + if len(accTxs) > 0 { + heads = append(heads, accTxs[0]) + // Ensure the sender address is from the signer + acc, _ := Sender(signer, accTxs[0]) + txs[acc] = accTxs[1:] + if from != acc { + delete(txs, from) + } } } heap.Init(&heads) @@ -450,40 +472,43 @@ func (t *TransactionsByPriceAndNonce) Pop() { // // NOTE: In a future PR this will be removed. type Message struct { - to *common.Address - l1MessageSender *common.Address - l1RollupTxId *hexutil.Uint64 - from common.Address - nonce uint64 - amount *big.Int - gasLimit uint64 - gasPrice *big.Int - data []byte - checkNonce bool + to *common.Address + l1MessageSender *common.Address + l1RollupTxId *hexutil.Uint64 + signatureHashType SignatureHashType + from common.Address + nonce uint64 + amount *big.Int + gasLimit uint64 + gasPrice *big.Int + data []byte + checkNonce bool } -func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, checkNonce bool, l1MessageSender *common.Address, l1RollupTxId *hexutil.Uint64) Message { +func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, checkNonce bool, l1MessageSender *common.Address, l1RollupTxId *hexutil.Uint64, signatureHashType SignatureHashType) Message { return Message{ - from: from, - to: to, - nonce: nonce, - amount: amount, - gasLimit: gasLimit, - gasPrice: gasPrice, - data: data, - checkNonce: checkNonce, - l1RollupTxId: l1RollupTxId, - l1MessageSender: l1MessageSender, + from: from, + to: to, + nonce: nonce, + amount: amount, + gasLimit: gasLimit, + gasPrice: gasPrice, + data: data, + checkNonce: checkNonce, + l1RollupTxId: l1RollupTxId, + l1MessageSender: l1MessageSender, + signatureHashType: signatureHashType, } } -func (m Message) From() common.Address { return m.from } -func (m Message) To() *common.Address { return m.to } -func (m Message) L1MessageSender() *common.Address { return m.l1MessageSender } -func (m Message) L1RollupTxId() *hexutil.Uint64 { return m.l1RollupTxId } -func (m Message) GasPrice() *big.Int { return m.gasPrice } -func (m Message) Value() *big.Int { return m.amount } -func (m Message) Gas() uint64 { return m.gasLimit } -func (m Message) Nonce() uint64 { return m.nonce } -func (m Message) Data() []byte { return m.data } -func (m Message) CheckNonce() bool { return m.checkNonce } +func (m Message) From() common.Address { return m.from } +func (m Message) To() *common.Address { return m.to } +func (m Message) L1MessageSender() *common.Address { return m.l1MessageSender } +func (m Message) L1RollupTxId() *hexutil.Uint64 { return m.l1RollupTxId } +func (m Message) SignatureHashType() SignatureHashType { return m.signatureHashType } +func (m Message) GasPrice() *big.Int { return m.gasPrice } +func (m Message) Value() *big.Int { return m.amount } +func (m Message) Gas() uint64 { return m.gasLimit } +func (m Message) Nonce() uint64 { return m.nonce } +func (m Message) Data() []byte { return m.data } +func (m Message) CheckNonce() bool { return m.checkNonce } diff --git a/core/types/transaction_meta.go b/core/types/transaction_meta.go new file mode 100644 index 000000000..c8dcb51c1 --- /dev/null +++ b/core/types/transaction_meta.go @@ -0,0 +1,104 @@ +/** + * Optimism 2020 Copyright + */ + +package types + +import ( + "bytes" + "encoding/binary" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +type TransactionMeta struct { + L1RollupTxId *hexutil.Uint64 `json:"l1RollupTxId"` + L1MessageSender *common.Address `json:"l1MessageSender"` + SignatureHashType SignatureHashType `json:"signatureHashType"` +} + +func NewTransactionMeta(L1RollupTxId *hexutil.Uint64, L1MessageSender *common.Address, sighashType SignatureHashType) *TransactionMeta { + return &TransactionMeta{L1RollupTxId: L1RollupTxId, L1MessageSender: L1MessageSender, SignatureHashType: sighashType} +} + +// TxMetaDecode deserializes bytes as a TransactionMeta struct. +// The schema is: +// varbytes(SignatureHashType) || varbytes(L1RollupTxId) || varbytes(L1MessageSender) +func TxMetaDecode(input []byte) (*TransactionMeta, error) { + var err error + meta := TransactionMeta{} + + b := bytes.NewReader(input) + + sb, err := common.ReadVarBytes(b, 0, 1024, "SignatureHashType") + if err != nil { + return &TransactionMeta{}, err + } + + var sighashType SignatureHashType + binary.Read(bytes.NewReader(sb), binary.LittleEndian, &sighashType) + meta.SignatureHashType = sighashType + + lb, err := common.ReadVarBytes(b, 0, 1024, "L1RollupTxId") + if err != nil { + return &TransactionMeta{}, err + } + + if !isNullValue(lb) { + var l1RollupTxId hexutil.Uint64 + binary.Read(bytes.NewReader(lb), binary.LittleEndian, &l1RollupTxId) + meta.L1RollupTxId = &l1RollupTxId + } + + mb, err := common.ReadVarBytes(b, 0, 1024, "L1MessageSender") + if err != nil { + return &TransactionMeta{}, err + } + + if !isNullValue(mb) { + var l1MessageSender common.Address + binary.Read(bytes.NewReader(mb), binary.LittleEndian, &l1MessageSender) + meta.L1MessageSender = &l1MessageSender + } + + return &meta, nil +} + +// TxMetaEncode serializes the TransactionMeta as bytes. +func TxMetaEncode(meta *TransactionMeta) []byte { + b := new(bytes.Buffer) + + s := new(bytes.Buffer) + binary.Write(s, binary.LittleEndian, &meta.SignatureHashType) + common.WriteVarBytes(b, 0, s.Bytes()) + + L1RollupTxId := meta.L1RollupTxId + if L1RollupTxId == nil { + common.WriteVarBytes(b, 0, getNullValue()) + } else { + l := new(bytes.Buffer) + binary.Write(l, binary.LittleEndian, *L1RollupTxId) + common.WriteVarBytes(b, 0, l.Bytes()) + } + + L1MessageSender := meta.L1MessageSender + if L1MessageSender == nil { + common.WriteVarBytes(b, 0, getNullValue()) + } else { + l := new(bytes.Buffer) + binary.Write(l, binary.LittleEndian, *L1MessageSender) + common.WriteVarBytes(b, 0, l.Bytes()) + } + + return b.Bytes() +} + +func isNullValue(b []byte) bool { + nullValue := []byte{0x00} + return bytes.Equal(b, nullValue) +} + +func getNullValue() []byte { + return []byte{0x00} +} diff --git a/core/types/transaction_meta_test.go b/core/types/transaction_meta_test.go new file mode 100644 index 000000000..ad735d50c --- /dev/null +++ b/core/types/transaction_meta_test.go @@ -0,0 +1,110 @@ +package types + +import ( + "bytes" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var ( + addr = common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") + txid = hexutil.Uint64(0) + + txMetaSerializationTests = []struct { + txid *hexutil.Uint64 + msgSender *common.Address + sighashType SignatureHashType + }{ + { + txid: &txid, + msgSender: &addr, + sighashType: SighashEthSign, + }, + { + txid: nil, + msgSender: &addr, + sighashType: SighashEthSign, + }, + { + txid: &txid, + msgSender: nil, + sighashType: SighashEthSign, + }, + } + + txMetaSighashEncodeTests = []struct { + input SignatureHashType + output SignatureHashType + }{ + { + input: SighashEIP155, + output: SighashEIP155, + }, + { + input: SighashEthSign, + output: SighashEthSign, + }, + } +) + +func TestTransactionMetaEncode(t *testing.T) { + for _, test := range txMetaSerializationTests { + txmeta := NewTransactionMeta(test.txid, test.msgSender, test.sighashType) + encoded := TxMetaEncode(txmeta) + decoded, err := TxMetaDecode(encoded) + + if err != nil { + t.Fatal(err) + } + + if !isTxMetaEqual(txmeta, decoded) { + t.Fatal("Encoding/decoding mismatch") + } + } +} + +func TestTransactionSighashEncode(t *testing.T) { + for _, test := range txMetaSighashEncodeTests { + txmeta := NewTransactionMeta(&txid, &addr, test.input) + encoded := TxMetaEncode(txmeta) + decoded, err := TxMetaDecode(encoded) + + if err != nil { + t.Fatal(err) + } + + if decoded.SignatureHashType != test.output { + t.Fatal("SighashTypes do not match") + } + } +} + +func isTxMetaEqual(meta1 *TransactionMeta, meta2 *TransactionMeta) bool { + if meta1.L1MessageSender == nil || meta2.L1MessageSender == nil { + if meta1.L1MessageSender != meta2.L1MessageSender { + return false + } + } else { + if !bytes.Equal(meta1.L1MessageSender.Bytes(), meta2.L1MessageSender.Bytes()) { + return false + } + } + + if meta1.L1RollupTxId == nil || meta2.L1RollupTxId == nil { + if meta1.L1RollupTxId != meta2.L1RollupTxId { + return false + } + } else { + if *meta1.L1RollupTxId != *meta2.L1RollupTxId { + return false + } + } + + if meta1.SignatureHashType != meta2.SignatureHashType { + return false + } + + return true +} diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 842fedbd0..abd27a0b1 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -17,7 +17,9 @@ package types import ( + "bytes" "crypto/ecdsa" + "encoding/binary" "errors" "fmt" "math/big" @@ -25,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" + "golang.org/x/crypto/sha3" ) var ( @@ -40,16 +43,7 @@ type sigCache struct { // MakeSigner returns a Signer based on the given chain config and block number. func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { - var signer Signer - switch { - case config.IsEIP155(blockNumber): - signer = NewEIP155Signer(config.ChainID) - case config.IsHomestead(blockNumber): - signer = HomesteadSigner{} - default: - signer = FrontierSigner{} - } - return signer + return NewOVMSigner(config.ChainID) } // SignTx signs the transaction using the given signer and private key @@ -102,6 +96,102 @@ type Signer interface { Equal(Signer) bool } +// OVMSigner implements Signers using the EIP155 rules along with a new +// `eth_sign` based signature hash. +type OVMSigner struct { + EIP155Signer +} + +func NewOVMSigner(chainId *big.Int) OVMSigner { + signer := NewEIP155Signer(chainId) + return OVMSigner{signer} +} + +func (s OVMSigner) Equal(s2 Signer) bool { + ovm, ok := s2.(OVMSigner) + return ok && ovm.chainId.Cmp(s.chainId) == 0 +} + +// Hash returns the hash to be signed by the sender. +// It does not uniquely identify the transaction. +func (s OVMSigner) Hash(tx *Transaction) common.Hash { + if tx.IsEthSignSighash() { + msg := s.OVMSignerTemplateSighashPreimage(tx) + + hasher := sha3.NewLegacyKeccak256() + hasher.Write(msg) + digest := hasher.Sum(nil) + + return common.BytesToHash(digest) + } + + return rlpHash([]interface{}{ + tx.data.AccountNonce, + tx.data.Price, + tx.data.GasLimit, + tx.data.Recipient, + tx.data.Amount, + tx.data.Payload, + s.chainId, uint(0), uint(0), + }) +} + +func (s OVMSigner) Sender(tx *Transaction) (common.Address, error) { + if !tx.Protected() { + return HomesteadSigner{}.Sender(tx) + } + if tx.ChainId().Cmp(s.chainId) != 0 { + return common.Address{}, ErrInvalidChainId + } + V := new(big.Int).Sub(tx.data.V, s.chainIdMul) + V.Sub(V, big8) + return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true) +} + +// OVMSignerTemplateSighashPreimage creates the preimage for the `eth_sign` like +// signature hash. The transaction is `ABI.encodePacked`. +func (s OVMSigner) OVMSignerTemplateSighashPreimage(tx *Transaction) []byte { + // Pad the nonce to 32 bytes + n := new(bytes.Buffer) + binary.Write(n, binary.BigEndian, tx.data.AccountNonce) + nonce := common.LeftPadBytes(n.Bytes(), 32) + + // Pad the gas limit to 32 bytes + g := new(bytes.Buffer) + binary.Write(g, binary.BigEndian, tx.data.GasLimit) + gasLimit := common.LeftPadBytes(g.Bytes(), 32) + + p := new(bytes.Buffer) + binary.Write(p, binary.BigEndian, tx.data.Price.Bytes()) + gasPrice := common.LeftPadBytes(p.Bytes(), 32) + + chainId := common.LeftPadBytes(s.chainId.Bytes(), 32) + + // This should always be 20 bytes + to := tx.data.Recipient.Bytes() + + // The signature hash commits to the nonce, gas limit, + // recipient and data + b := new(bytes.Buffer) + binary.Write(b, binary.BigEndian, nonce) + binary.Write(b, binary.BigEndian, gasLimit) + binary.Write(b, binary.BigEndian, gasPrice) + binary.Write(b, binary.BigEndian, chainId) + binary.Write(b, binary.BigEndian, to) + binary.Write(b, binary.BigEndian, tx.data.Payload) + + hasher := sha3.NewLegacyKeccak256() + hasher.Write(b.Bytes()) + digest := hasher.Sum(nil) + + preimage := new(bytes.Buffer) + prefix := []byte("\x19Ethereum Signed Message:\n32") + binary.Write(preimage, binary.BigEndian, prefix) + binary.Write(preimage, binary.BigEndian, digest) + + return preimage.Bytes() +} + // EIP155Transaction implements Signer using the EIP155 rules. type EIP155Signer struct { chainId, chainIdMul *big.Int diff --git a/core/types/transaction_signing_test.go b/core/types/transaction_signing_test.go index 0ecdcc4d0..81f746ea3 100644 --- a/core/types/transaction_signing_test.go +++ b/core/types/transaction_signing_test.go @@ -30,7 +30,7 @@ func TestEIP155Signing(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) signer := NewEIP155Signer(big.NewInt(18)) - tx, err := SignTx(NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil), signer, key) + tx, err := SignTx(NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil, SighashEIP155), signer, key) if err != nil { t.Fatal(err) } @@ -49,7 +49,7 @@ func TestEIP155ChainId(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) signer := NewEIP155Signer(big.NewInt(18)) - tx, err := SignTx(NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil), signer, key) + tx, err := SignTx(NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil, SighashEIP155), signer, key) if err != nil { t.Fatal(err) } @@ -61,7 +61,7 @@ func TestEIP155ChainId(t *testing.T) { t.Error("expected chainId to be", signer.chainId, "got", tx.ChainId()) } - tx = NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil) + tx = NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil, SighashEIP155) tx, err = SignTx(tx, HomesteadSigner{}, key) if err != nil { t.Fatal(err) @@ -118,7 +118,7 @@ func TestEIP155SigningVitalik(t *testing.T) { func TestChainId(t *testing.T) { key, _ := defaultTestKey() - tx := NewTransaction(0, common.Address{}, new(big.Int), 0, new(big.Int), nil, nil, nil) + tx := NewTransaction(0, common.Address{}, new(big.Int), 0, new(big.Int), nil, nil, nil, SighashEIP155) var err error tx, err = SignTx(tx, NewEIP155Signer(big.NewInt(1)), key) @@ -136,3 +136,94 @@ func TestChainId(t *testing.T) { t.Error("expected no error") } } + +func TestOVMSigner(t *testing.T) { + key, _ := defaultTestKey() + + tx := NewTransaction(0, common.Address{}, new(big.Int), 0, new(big.Int), nil, nil, nil, SighashEthSign) + + var err error + tx, err = SignTx(tx, NewOVMSigner(big.NewInt(1)), key) + if err != nil { + t.Fatal(err) + } + + _, err = Sender(NewOVMSigner(big.NewInt(2)), tx) + if err != ErrInvalidChainId { + t.Error("expected error:", ErrInvalidChainId) + } + + _, err = Sender(NewOVMSigner(big.NewInt(1)), tx) + if err != nil { + t.Error("expected no error") + } +} + +func TestOVMSignerHash(t *testing.T) { + signer := NewOVMSigner(big.NewInt(1)) + + txNil := NewTransaction(0, common.Address{}, new(big.Int), 0, new(big.Int), nil, nil, nil, SighashEIP155) + txEIP155 := NewTransaction(0, common.Address{}, new(big.Int), 0, new(big.Int), nil, nil, nil, SighashEIP155) + + hashNil := signer.Hash(txNil) + hashEIP155 := signer.Hash(txEIP155) + if hashNil != hashEIP155 { + t.Errorf("Signature hashes should be equal: %s != %s", hashNil.Hex(), hashEIP155.Hex()) + } + + // The signature hash should be different when using `SighashEthSign` + txEthSign := NewTransaction(0, common.Address{}, new(big.Int), 0, new(big.Int), nil, nil, nil, SighashEthSign) + + hashEthSign := signer.Hash(txEthSign) + if hashEIP155 == hashEthSign { + t.Errorf("Signature hashes should not be equal: %s == %s", hashEIP155.Hex(), hashEthSign.Hex()) + } +} + +func TestOVMSignerSender(t *testing.T) { + // Create a keypair to sign transactions with and the corresponding address + // from the public key. + key, _ := crypto.GenerateKey() + addr := crypto.PubkeyToAddress(key.PublicKey) + + // This test makes sure that both the EIP155 and EthSign signature hash + // codepaths work when using the OVMSigner. + signer := NewOVMSigner(big.NewInt(1)) + var err error + + // Create a transaction with EIP155 signature hash, sign the transaction, + // recover the address and assert that the address matches the key. + txEIP155 := NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil, SighashEIP155) + + txEIP155, err = SignTx(txEIP155, signer, key) + if err != nil { + t.Errorf("No error expected") + } + + recEIP155, err := signer.Sender(txEIP155) + if err != nil { + t.Errorf("No error expected") + } + + if addr != recEIP155 { + t.Errorf("Recovered address doesn't match. Got %s, expected %s", recEIP155.Hex(), addr.Hex()) + } + + // Create a transaction with EthSign signature hash, sign the transaction, + // recover the address and assert that the address matches the key. + txEthSign := NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil, SighashEthSign) + + txEthSign, err = SignTx(txEthSign, signer, key) + if err != nil { + t.Errorf("No error expected") + } + + recEthSign, err := signer.Sender(txEthSign) + if err != nil { + t.Errorf("No error expected") + } + + if addr != recEthSign { + t.Errorf("Recovered address doesn't match. Got %s, expected %s", recEthSign.Hex(), addr.Hex()) + } +} diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 462dfe937..2411e7ec7 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -35,23 +35,25 @@ import ( var ( sender = common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") l1RollupTxId = hexutil.Uint64(1) - emptyTx = NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(0), 0, big.NewInt(0), nil, &sender, nil) - emptyTxEmptyL1Sender = NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(0), 0, big.NewInt(0), nil, nil, nil) + emptyTx = NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(0), 0, big.NewInt(0), nil, &sender, nil, SighashEIP155) + emptyTxEmptyL1Sender = NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(0), 0, big.NewInt(0), nil, nil, nil, SighashEIP155) - rightvrsTx, _ = NewTransaction(3, common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"), big.NewInt(10), 2000, big.NewInt(1), common.FromHex("5544"), nil, nil).WithSignature( + rightvrsTx, _ = NewTransaction(3, common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"), big.NewInt(10), 2000, big.NewInt(1), common.FromHex("5544"), nil, nil, SighashEIP155).WithSignature( HomesteadSigner{}, common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a301"), ) - rightvrsTxWithL1Sender, _ = NewTransaction(3, common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"), big.NewInt(10), 2000, big.NewInt(1), common.FromHex("5544"), &sender, nil).WithSignature( + rightvrsTxWithL1Sender, _ = NewTransaction(3, common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"), big.NewInt(10), 2000, big.NewInt(1), common.FromHex("5544"), &sender, nil, SighashEIP155).WithSignature( HomesteadSigner{}, common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a301"), ) - rightvrsTxWithL1RollupTxId, _ = NewTransaction(3, common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"), big.NewInt(10), 2000, big.NewInt(1), common.FromHex("5544"), nil, &l1RollupTxId).WithSignature( + rightvrsTxWithL1RollupTxId, _ = NewTransaction(3, common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"), big.NewInt(10), 2000, big.NewInt(1), common.FromHex("5544"), nil, &l1RollupTxId, SighashEIP155).WithSignature( HomesteadSigner{}, common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a301"), ) + + emptyTxSighashEthSign = NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(0), 0, big.NewInt(0), nil, &sender, nil, SighashEthSign) ) func TestTransactionSigHash(t *testing.T) { @@ -78,16 +80,29 @@ func TestTransactionEncode(t *testing.T) { if err != nil { t.Fatalf("encode error: %v", err) } - if bytes.Equal(txc, should) { - t.Errorf("RLP encoding with L1MessageSender should be different than without. Got %x", txc) + if !bytes.Equal(txc, should) { + t.Errorf("RLP encoding with L1MessageSender should be the same. Got %x", txc) } txd, err := rlp.EncodeToBytes(rightvrsTxWithL1RollupTxId) if err != nil { t.Fatalf("encode error: %v", err) } - if bytes.Equal(txd, should) { - t.Errorf("RLP encoding with L1MessageSender should be different than without. Got %x", txd) + if !bytes.Equal(txd, should) { + t.Errorf("RLP encoding with L1MessageSender should be the same. Got %x", txd) + } + + txe, err := rlp.EncodeToBytes(emptyTx) + if err != nil { + t.Fatalf("encode error: %v", err) + } + + txf, err := rlp.EncodeToBytes(emptyTxSighashEthSign) + if err != nil { + t.Fatalf("encode error: %v", err) + } + if !bytes.Equal(txe, txf) { + t.Error("RLP encoding with SighashEthSign should be the same") } } @@ -153,7 +168,7 @@ func TestTransactionPriceNonceSort(t *testing.T) { for start, key := range keys { addr := crypto.PubkeyToAddress(key.PublicKey) for i := 0; i < 25; i++ { - tx, _ := SignTx(NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), 100, big.NewInt(int64(start+i)), nil, nil, nil), signer, key) + tx, _ := SignTx(NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), 100, big.NewInt(int64(start+i)), nil, nil, nil, SighashEIP155), signer, key) groups[addr] = append(groups[addr], tx) } } @@ -197,14 +212,14 @@ func TestTransactionJSON(t *testing.T) { if err != nil { t.Fatalf("could not generate key: %v", err) } - signer := NewEIP155Signer(common.Big1) + signer := NewOVMSigner(common.Big1) transactions := make([]*Transaction, 0, 50) for i := uint64(0); i < 25; i++ { var tx *Transaction switch i % 2 { case 0: - tx = NewTransaction(i, common.Address{1}, common.Big0, 1, common.Big2, []byte("abcdef"), &sender, &l1RollupTxId) + tx = NewTransaction(i, common.Address{1}, common.Big0, 1, common.Big2, []byte("abcdef"), &sender, &l1RollupTxId, SighashEIP155) case 1: tx = NewContractCreation(i, common.Big0, 1, common.Big2, []byte("abcdef"), nil, nil) } @@ -245,8 +260,8 @@ func TestTransactionJSON(t *testing.T) { } } -// Tests that L1MessageSender has no impact on hash -func TestL1MessageSenderHash(t *testing.T) { +// Tests that OVM metadata has no impact on hash +func TestOVMMetaDataHash(t *testing.T) { if rightvrsTx.Hash() != rightvrsTxWithL1Sender.Hash() { t.Errorf("L1MessageSender, should not affect the hash, want %x, got %x with L1MessageSender", rightvrsTx.Hash(), rightvrsTxWithL1Sender.Hash()) } @@ -258,4 +273,8 @@ func TestL1MessageSenderHash(t *testing.T) { if emptyTx.Hash() != emptyTxEmptyL1Sender.Hash() { t.Errorf("L1MessageSender, should not affect the hash, want %x, got %x with L1MessageSender", emptyTx.Hash(), emptyTxEmptyL1Sender.Hash()) } + + if emptyTx.Hash() != emptyTxSighashEthSign.Hash() { + t.Errorf("SignatureHashType, should not affect the hash, want %x, got %x with SighashEthSign", emptyTx.Hash(), emptyTxSighashEthSign.Hash()) + } } diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index 18f5fe637..5aadc7472 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -131,7 +131,7 @@ func (tc *testChain) generate(n int, seed byte, parent *types.Block, heavy bool) signer := types.MakeSigner(params.TestChainConfig, block.Number()) l1Sender := common.Address{seed} l1RollupTxId := hexutil.Uint64(22) - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil, &l1Sender, &l1RollupTxId), signer, testKey) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil, &l1Sender, &l1RollupTxId, types.SighashEIP155), signer, testKey) if err != nil { panic(err) } diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go index 0f8bb695e..dfd1cffae 100644 --- a/eth/fetcher/fetcher_test.go +++ b/eth/fetcher/fetcher_test.go @@ -52,7 +52,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common // If the block number is multiple of 3, send a bonus transaction to the miner if parent == genesis && i%3 == 0 { signer := types.MakeSigner(params.TestChainConfig, block.Number()) - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, testKey) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, testKey) if err != nil { panic(err) } diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 649c0421f..3172ae335 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -218,11 +218,11 @@ func TestPendingTxFilter(t *testing.T) { api = NewPublicFilterAPI(backend, false) transactions = []*types.Transaction{ - types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil), - types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil), - types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil), - types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil), - types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil), + types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil, types.SighashEIP155), + types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil, types.SighashEIP155), + types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil, types.SighashEIP155), + types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil, types.SighashEIP155), + types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil, types.SighashEIP155), } hashes []common.Hash diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 5b6cb3077..ec88a13e5 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -127,7 +127,7 @@ func TestFilters(t *testing.T) { }, } gen.AddUncheckedReceipt(receipt) - gen.AddUncheckedTx(types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil, nil, nil)) + gen.AddUncheckedTx(types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil, nil, nil, types.SighashEIP155)) case 2: receipt := types.NewReceipt(nil, false, 0) receipt.Logs = []*types.Log{ @@ -137,7 +137,7 @@ func TestFilters(t *testing.T) { }, } gen.AddUncheckedReceipt(receipt) - gen.AddUncheckedTx(types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil, nil, nil)) + gen.AddUncheckedTx(types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil, nil, nil, types.SighashEIP155)) case 998: receipt := types.NewReceipt(nil, false, 0) @@ -148,7 +148,7 @@ func TestFilters(t *testing.T) { }, } gen.AddUncheckedReceipt(receipt) - gen.AddUncheckedTx(types.NewTransaction(998, common.HexToAddress("0x998"), big.NewInt(998), 998, big.NewInt(998), nil, nil, nil)) + gen.AddUncheckedTx(types.NewTransaction(998, common.HexToAddress("0x998"), big.NewInt(998), 998, big.NewInt(998), nil, nil, nil, types.SighashEIP155)) case 999: receipt := types.NewReceipt(nil, false, 0) receipt.Logs = []*types.Log{ @@ -158,7 +158,7 @@ func TestFilters(t *testing.T) { }, } gen.AddUncheckedReceipt(receipt) - gen.AddUncheckedTx(types.NewTransaction(999, common.HexToAddress("0x999"), big.NewInt(999), 999, big.NewInt(999), nil, nil, nil)) + gen.AddUncheckedTx(types.NewTransaction(999, common.HexToAddress("0x999"), big.NewInt(999), 999, big.NewInt(999), nil, nil, nil, types.SighashEIP155)) } }) for i, block := range chain { diff --git a/eth/handler_test.go b/eth/handler_test.go index c28ebb0bb..ec55a69ff 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -290,13 +290,13 @@ func testGetNodeData(t *testing.T, protocol int) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) - tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, acc1Key) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: @@ -389,13 +389,13 @@ func testGetReceipt(t *testing.T, protocol int) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) - tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, acc1Key) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: diff --git a/eth/helper_test.go b/eth/helper_test.go index 031f0650d..6b06fdc5d 100644 --- a/eth/helper_test.go +++ b/eth/helper_test.go @@ -134,7 +134,7 @@ func (p *testTxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subs // newTestTransaction create a new dummy transaction. func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction { - tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), 100000, big.NewInt(0), make([]byte, datasize), nil, nil) + tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), 100000, big.NewInt(0), make([]byte, datasize), nil, nil, types.SighashEIP155) tx, _ = types.SignTx(tx, types.HomesteadSigner{}, from) return tx } diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 0c7463f42..af59e6e39 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -123,7 +123,7 @@ type callTracerTest struct { func TestPrestateTracerCreate2(t *testing.T) { t.Skip("OVM breaks this with `cannot read property` error, probably related to state manager.") - unsignedTx := types.NewTransaction(1, common.HexToAddress("0x00000000000000000000000000000000deadbeef"), new(big.Int), 5000000, big.NewInt(1), []byte{}, nil, nil) + unsignedTx := types.NewTransaction(1, common.HexToAddress("0x00000000000000000000000000000000deadbeef"), new(big.Int), 5000000, big.NewInt(1), []byte{}, nil, nil, types.SighashEIP155) privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) if err != nil { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1d40a3153..965f45c61 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -830,7 +830,7 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo } // Create new call message - msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false, nil, nil) + msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false, nil, nil, 0) // Setup context so it may be cancelled the call has completed // or, in case of unmetered gas, setup a context with a timeout. @@ -1117,9 +1117,10 @@ type RPCTransaction struct { // newRPCTransaction returns a transaction that will serialize to the RPC // representation, with the given location metadata set (if available). func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction { + // TODO(mark): the transaction must be protected var signer types.Signer = types.FrontierSigner{} if tx.Protected() { - signer = types.NewEIP155Signer(tx.ChainId()) + signer = types.NewOVMSigner(tx.ChainId()) } from, _ := types.Sender(signer, tx) v, r, s := tx.RawSignatureValues() @@ -1269,6 +1270,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { // Try to return an already finalized transaction tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) + if err != nil { return nil, err } @@ -1318,7 +1320,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha var signer types.Signer = types.FrontierSigner{} if tx.Protected() { - signer = types.NewEIP155Signer(tx.ChainId()) + signer = types.NewOVMSigner(tx.ChainId()) } from, _ := types.Sender(signer, tx) @@ -1375,10 +1377,11 @@ type SendTxArgs struct { Nonce *hexutil.Uint64 `json:"nonce"` // We accept "data" and "input" for backwards-compatibility reasons. "input" is the // newer name and should be preferred by clients. - Data *hexutil.Bytes `json:"data"` - Input *hexutil.Bytes `json:"input"` - L1RollupTxId *hexutil.Uint64 `json:"l1RollupTxId,omitempty" rlp:"nil,?"` - L1MessageSender *common.Address `json:"l1MessageSender,omitempty" rlp:"nil,?"` + Data *hexutil.Bytes `json:"data"` + Input *hexutil.Bytes `json:"input"` + L1RollupTxId *hexutil.Uint64 `json:"l1RollupTxId,omitempty"` + L1MessageSender *common.Address `json:"l1MessageSender,omitempty"` + SignatureHashType types.SignatureHashType `json:"signatureHashType,omitempty"` } // setDefaults is a helper function that fills in default values for unspecified tx fields. @@ -1451,7 +1454,7 @@ func (args *SendTxArgs) toTransaction() *types.Transaction { if args.To == nil { return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input, nil, args.L1RollupTxId) } - return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input, args.L1MessageSender, args.L1RollupTxId) + return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input, args.L1MessageSender, args.L1RollupTxId, args.SignatureHashType) } type RollupTransaction struct { @@ -1471,7 +1474,7 @@ func (r *RollupTransaction) toTransaction(txNonce uint64) *types.Transaction { if r.Target == nil { tx = types.NewContractCreation(txNonce, big.NewInt(0), uint64(*r.GasLimit), big.NewInt(0), c, r.Sender, r.L1RollupTxId) } else { - tx = types.NewTransaction(txNonce, *r.Target, big.NewInt(0), uint64(*r.GasLimit), big.NewInt(0), c, r.Sender, r.L1RollupTxId) + tx = types.NewTransaction(txNonce, *r.Target, big.NewInt(0), uint64(*r.GasLimit), big.NewInt(0), c, r.Sender, r.L1RollupTxId, types.SighashEIP155) } tx.AddNonceToWrappedTransaction(uint64(*r.Nonce)) return tx @@ -1561,7 +1564,21 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod return SubmitTransaction(ctx, s.b, tx) } -// SendBlockBatches will: +// SendRawEthSignTransaction will add the signed transaction to the mempool. +// The signature hash was computed with `eth_sign`, meaning that the +// `abi.encodedPacked` transaction was prefixed with the string +// "Ethereum Signed Message". +func (s *PublicTransactionPoolAPI) SendRawEthSignTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) { + tx := new(types.Transaction) + if err := rlp.DecodeBytes(encodedTx, tx); err != nil { + return common.Hash{}, err + } + + tx.SetSignatureHashType(types.SighashEthSign) + return SubmitTransaction(ctx, s.b, tx) +} + +// SendRollupTransactions will: // * Verify the batches are signed by the RollupTransaction sender. // * Update the Geth timestamp to the provided timestamp // * handle the provided batch of RollupTransactions atomically @@ -1680,7 +1697,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err for _, tx := range pending { var signer types.Signer = types.HomesteadSigner{} if tx.Protected() { - signer = types.NewEIP155Signer(tx.ChainId()) + signer = types.NewOVMSigner(tx.ChainId()) } from, _ := types.Sender(signer, tx) if _, exists := accounts[from]; exists { @@ -1708,7 +1725,7 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr for _, p := range pending { var signer types.Signer = types.HomesteadSigner{} if p.Protected() { - signer = types.NewEIP155Signer(p.ChainId()) + signer = types.NewOVMSigner(p.ChainId()) } wantSigHash := signer.Hash(matchTx) diff --git a/les/benchmark.go b/les/benchmark.go index d33baf5b4..247030605 100644 --- a/les/benchmark.go +++ b/les/benchmark.go @@ -180,7 +180,7 @@ func (b *benchmarkTxSend) init(h *serverHandler, count int) error { for i := range b.txs { data := make([]byte, txSizeCostLimit) rand.Read(data) - tx, err := types.SignTx(types.NewTransaction(0, addr, new(big.Int), 0, new(big.Int), data, nil, nil), signer, key) + tx, err := types.SignTx(types.NewTransaction(0, addr, new(big.Int), 0, new(big.Int), data, nil, nil, types.SighashEIP155), signer, key) if err != nil { panic(err) } diff --git a/les/handler_test.go b/les/handler_test.go index 2be725406..c14394720 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -556,16 +556,16 @@ func testTransactionStatus(t *testing.T, protocol int) { signer := types.HomesteadSigner{} // test error status by sending an underpriced transaction - tx0, _ := types.SignTx(types.NewTransaction(0, userAddr1, big.NewInt(10000), params.TxGas, nil, nil, nil, nil), signer, bankKey) + tx0, _ := types.SignTx(types.NewTransaction(0, userAddr1, big.NewInt(10000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, bankKey) test(tx0, true, light.TxStatus{Status: core.TxStatusUnknown, Error: core.ErrUnderpriced.Error()}) - tx1, _ := types.SignTx(types.NewTransaction(0, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil), signer, bankKey) + tx1, _ := types.SignTx(types.NewTransaction(0, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil, types.SighashEIP155), signer, bankKey) test(tx1, false, light.TxStatus{Status: core.TxStatusUnknown}) // query before sending, should be unknown test(tx1, true, light.TxStatus{Status: core.TxStatusPending}) // send valid processable tx, should return pending test(tx1, true, light.TxStatus{Status: core.TxStatusPending}) // adding it again should not return an error - tx2, _ := types.SignTx(types.NewTransaction(1, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil), signer, bankKey) - tx3, _ := types.SignTx(types.NewTransaction(2, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil), signer, bankKey) + tx2, _ := types.SignTx(types.NewTransaction(1, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil, types.SighashEIP155), signer, bankKey) + tx3, _ := types.SignTx(types.NewTransaction(2, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil, types.SighashEIP155), signer, bankKey) // send transactions in the wrong order, tx3 should be queued test(tx3, true, light.TxStatus{Status: core.TxStatusQueued}) test(tx2, true, light.TxStatus{Status: core.TxStatusPending}) diff --git a/les/odr_test.go b/les/odr_test.go index c5d1dab23..eecd12337 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -160,7 +160,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai from := statedb.GetOrNewStateObject(bankAddr) from.SetBalance(math.MaxBig256) - msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false, nil, nil)} + msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false, nil, nil, 0)} context := core.NewEVMContext(msg, header, bc, nil) vmenv := vm.NewEVM(context, statedb, config, vm.Config{}) @@ -174,7 +174,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai header := lc.GetHeaderByHash(bhash) state := light.NewState(ctx, header, lc.Odr()) state.SetBalance(bankAddr, math.MaxBig256) - msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false, nil, nil)} + msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false, nil, nil, 0)} context := core.NewEVMContext(msg, header, lc, nil) vmenv := vm.NewEVM(context, state, config, vm.Config{}) gp := new(core.GasPool).AddGas(math.MaxUint64) diff --git a/les/test_helper.go b/les/test_helper.go index 176bb728b..4c79f49e8 100644 --- a/les/test_helper.go +++ b/les/test_helper.go @@ -112,18 +112,18 @@ func prepare(n int, backend *backends.SimulatedBackend) { registrarAddr, _, _, _ = contract.DeployCheckpointOracle(bind.NewKeyedTransactor(bankKey), backend, []common.Address{signerAddr}, sectionSize, processConfirms, big.NewInt(1)) // bankUser transfers some ether to user1 nonce, _ := backend.PendingNonceAt(ctx, bankAddr) - tx, _ := types.SignTx(types.NewTransaction(nonce, userAddr1, big.NewInt(10000), params.TxGas, nil, nil, nil, nil), signer, bankKey) + tx, _ := types.SignTx(types.NewTransaction(nonce, userAddr1, big.NewInt(10000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, bankKey) backend.SendTransaction(ctx, tx) case 1: bankNonce, _ := backend.PendingNonceAt(ctx, bankAddr) userNonce1, _ := backend.PendingNonceAt(ctx, userAddr1) // bankUser transfers more ether to user1 - tx1, _ := types.SignTx(types.NewTransaction(bankNonce, userAddr1, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, bankKey) + tx1, _ := types.SignTx(types.NewTransaction(bankNonce, userAddr1, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, bankKey) backend.SendTransaction(ctx, tx1) // user1 relays ether to user2 - tx2, _ := types.SignTx(types.NewTransaction(userNonce1, userAddr2, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, userKey1) + tx2, _ := types.SignTx(types.NewTransaction(userNonce1, userAddr2, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, userKey1) backend.SendTransaction(ctx, tx2) // user1 deploys a test contract @@ -137,18 +137,18 @@ func prepare(n int, backend *backends.SimulatedBackend) { case 2: // bankUser transfer some ether to signer bankNonce, _ := backend.PendingNonceAt(ctx, bankAddr) - tx1, _ := types.SignTx(types.NewTransaction(bankNonce, signerAddr, big.NewInt(1000000000), params.TxGas, nil, nil, nil, nil), signer, bankKey) + tx1, _ := types.SignTx(types.NewTransaction(bankNonce, signerAddr, big.NewInt(1000000000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, bankKey) backend.SendTransaction(ctx, tx1) // invoke test contract data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") - tx2, _ := types.SignTx(types.NewTransaction(bankNonce+1, testContractAddr, big.NewInt(0), 100000, nil, data, nil, nil), signer, bankKey) + tx2, _ := types.SignTx(types.NewTransaction(bankNonce+1, testContractAddr, big.NewInt(0), 100000, nil, data, nil, nil, types.SighashEIP155), signer, bankKey) backend.SendTransaction(ctx, tx2) case 3: // invoke test contract bankNonce, _ := backend.PendingNonceAt(ctx, bankAddr) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") - tx, _ := types.SignTx(types.NewTransaction(bankNonce, testContractAddr, big.NewInt(0), 100000, nil, data, nil, nil), signer, bankKey) + tx, _ := types.SignTx(types.NewTransaction(bankNonce, testContractAddr, big.NewInt(0), 100000, nil, data, nil, nil, types.SighashEIP155), signer, bankKey) backend.SendTransaction(ctx, tx) } backend.Commit() diff --git a/light/odr_test.go b/light/odr_test.go index 265ab7b38..a8d7b948f 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -194,7 +194,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain // Perform read-only call. st.SetBalance(testBankAddress, math.MaxBig256) - msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false, nil, nil)} + msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false, nil, nil, 0)} context := core.NewEVMContext(msg, header, chain, nil) vmenv := vm.NewEVM(context, st, config, vm.Config{}) gp := new(core.GasPool).AddGas(math.MaxUint64) @@ -212,15 +212,15 @@ func testChainGen(i int, block *core.BlockGen) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. // acc1Addr creates a test contract. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, testBankKey) nonce := block.TxNonce(acc1Addr) - tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, acc1Key) + tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), signer, acc1Key) nonce++ tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), testContractCode, nil, nil), signer, acc1Key) testContractAddr = crypto.CreateAddress(acc1Addr, nonce) @@ -232,7 +232,7 @@ func testChainGen(i int, block *core.BlockGen) { block.SetCoinbase(acc2Addr) block.SetExtra([]byte("yeehaw")) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, data, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, data, nil, nil, types.SighashEIP155), signer, testBankKey) block.AddTx(tx) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). @@ -243,7 +243,7 @@ func testChainGen(i int, block *core.BlockGen) { b3.Extra = []byte("foo") block.AddUncle(b3) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, data, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, data, nil, nil, types.SighashEIP155), signer, testBankKey) block.AddTx(tx) } } diff --git a/light/txpool_test.go b/light/txpool_test.go index 394600395..285d851e1 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -77,7 +77,7 @@ func txPoolTestChainGen(i int, block *core.BlockGen) { func TestTxPool(t *testing.T) { for i := range testTx { - testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil), types.HomesteadSigner{}, testBankKey) + testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), types.HomesteadSigner{}, testBankKey) } var ( diff --git a/miner/worker_test.go b/miner/worker_test.go index 717a01ebf..c7d30e365 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -82,9 +82,9 @@ func init() { Period: 10, Epoch: 30000, } - tx1, _ := types.SignTx(types.NewTransaction(0, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), types.HomesteadSigner{}, testBankKey) + tx1, _ := types.SignTx(types.NewTransaction(0, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), types.HomesteadSigner{}, testBankKey) pendingTxs = append(pendingTxs, tx1) - tx2, _ := types.SignTx(types.NewTransaction(1, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), types.HomesteadSigner{}, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(1, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), types.HomesteadSigner{}, testBankKey) newTxs = append(newTxs, tx2) rand.Seed(time.Now().UnixNano()) } @@ -171,7 +171,7 @@ func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction { if creation { tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, nil, common.FromHex(testCode), nil, nil), types.HomesteadSigner{}, testBankKey) } else { - tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), types.HomesteadSigner{}, testBankKey) + tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, types.SighashEIP155), types.HomesteadSigner{}, testBankKey) } return tx } diff --git a/mobile/types.go b/mobile/types.go index 508a6bcdc..066206e9f 100644 --- a/mobile/types.go +++ b/mobile/types.go @@ -203,7 +203,7 @@ func NewTransaction(nonce int64, to *Address, amount *BigInt, gasLimit int64, ga if to == nil { return &Transaction{types.NewContractCreation(uint64(nonce), amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data), nil, nil)} } - return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data), nil, nil)} + return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data), nil, nil, types.SighashEIP155)} } // NewTransactionFromRLP parses a transaction from an RLP data dump. diff --git a/rollup/transition_batch_builder_test.go b/rollup/transition_batch_builder_test.go index f9e9ad886..d5482ce78 100644 --- a/rollup/transition_batch_builder_test.go +++ b/rollup/transition_batch_builder_test.go @@ -78,7 +78,7 @@ func createBlocks(number int, startIndex int, withTx bool) types.Blocks { header := &types.Header{Number: big.NewInt(int64(i + startIndex))} txs := make(types.Transactions, 0) if withTx { - tx, _ := types.SignTx(types.NewTransaction(uint64(i), testUserAddress, big.NewInt(1), params.TxGas, big.NewInt(0), nil, &testUserAddress, &testRollupTxId), types.HomesteadSigner{}, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(uint64(i), testUserAddress, big.NewInt(1), params.TxGas, big.NewInt(0), nil, &testUserAddress, &testRollupTxId, types.SighashEIP155), types.HomesteadSigner{}, testBankKey) txs = append(txs, tx) } block := types.NewBlock(header, txs, make([]*types.Header, 0), make([]*types.Receipt, 0)) diff --git a/signer/core/types.go b/signer/core/types.go index bc3ef6efc..1b8c3ea6c 100644 --- a/signer/core/types.go +++ b/signer/core/types.go @@ -74,10 +74,11 @@ type SendTxArgs struct { Value hexutil.Big `json:"value"` Nonce hexutil.Uint64 `json:"nonce"` // We accept "data" and "input" for backwards-compatibility reasons. - Data *hexutil.Bytes `json:"data"` - Input *hexutil.Bytes `json:"input,omitempty"` - L1MessageSender *common.MixedcaseAddress `json:"l1MessageSender,omitempty" rlp:"nil,?"` - L1RollupTxId *hexutil.Uint64 `json:"l1RollupTxId,omitempty" rlp:"nil,?"` + Data *hexutil.Bytes `json:"data"` + Input *hexutil.Bytes `json:"input,omitempty"` + L1MessageSender *common.MixedcaseAddress `json:"l1MessageSender,omitempty"` + L1RollupTxId *hexutil.Uint64 `json:"l1RollupTxId,omitempty"` + SignatureHashType types.SignatureHashType `json:"signatureHashType,omitempty"` } func (args SendTxArgs) String() string { @@ -105,5 +106,6 @@ func (args *SendTxArgs) toTransaction() *types.Transaction { l1RollupTxId = new(hexutil.Uint64) *l1RollupTxId = *args.L1RollupTxId } - return types.NewTransaction(uint64(args.Nonce), args.To.Address(), (*big.Int)(&args.Value), (uint64)(args.Gas), (*big.Int)(&args.GasPrice), input, l1MessageSender, l1RollupTxId) + + return types.NewTransaction(uint64(args.Nonce), args.To.Address(), (*big.Int)(&args.Value), (uint64)(args.Gas), (*big.Int)(&args.GasPrice), input, l1MessageSender, l1RollupTxId, args.SignatureHashType) } diff --git a/signer/rules/rules_test.go b/signer/rules/rules_test.go index 159e16fda..a0b95ff4b 100644 --- a/signer/rules/rules_test.go +++ b/signer/rules/rules_test.go @@ -458,7 +458,7 @@ func dummySigned(value *big.Int) *types.Transaction { gas := uint64(21000) gasPrice := big.NewInt(2000000) data := make([]byte, 0) - return types.NewTransaction(3, to, value, gas, gasPrice, data, nil, nil) + return types.NewTransaction(3, to, value, gas, gasPrice, data, nil, nil, types.SighashEIP155) } func TestLimitWindow(t *testing.T) { diff --git a/tests/ovm_test.go b/tests/ovm_test.go index 0e373e9c0..24b909615 100644 --- a/tests/ovm_test.go +++ b/tests/ovm_test.go @@ -241,6 +241,7 @@ func applyMessageToState(currentState *state.StateDB, from common.Address, to co false, &ZERO_ADDRESS, nil, + 0, ) } else { // Otherwise we actually use the `to` field! @@ -255,6 +256,7 @@ func applyMessageToState(currentState *state.StateDB, from common.Address, to co false, &ZERO_ADDRESS, nil, + 0, ) } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 19d3689e2..f59e76832 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -279,7 +279,7 @@ func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) { return nil, fmt.Errorf("invalid tx data %q", dataHex) } - msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, true, nil, nil) + msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, true, nil, nil, 0) return msg, nil }