From 694bf695cd9207a0810836c4c60e3d49c0cb47e7 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Mon, 18 Oct 2021 12:42:30 -0500 Subject: [PATCH] Expand custom arb tx types --- core/types/arb_types.go | 86 +++++++++++++++++-------------- core/types/arbitrum_signer.go | 6 +-- core/types/transaction.go | 44 ++++++++++++++-- core/types/transaction_signing.go | 12 ++++- 4 files changed, 100 insertions(+), 48 deletions(-) diff --git a/core/types/arb_types.go b/core/types/arb_types.go index f4f6f7d4f834..38aae54501fc 100644 --- a/core/types/arb_types.go +++ b/core/types/arb_types.go @@ -8,13 +8,13 @@ import ( var bigZero = big.NewInt(0) -func (tx *LegacyTx) isFake() bool { return false } +func (tx *LegacyTx) isFake() bool { return false } func (tx *AccessListTx) isFake() bool { return false } func (tx *DynamicFeeTx) isFake() bool { return false } type ArbitrumUnsignedTx struct { ChainId *big.Int - From common.Address + From common.Address Nonce uint64 // nonce of sender account GasPrice *big.Int // wei per gas @@ -24,18 +24,17 @@ type ArbitrumUnsignedTx struct { Data []byte // contract invocation input data } - func (tx *ArbitrumUnsignedTx) txType() byte { return ArbitrumUnsignedTxType } func (tx *ArbitrumUnsignedTx) copy() TxData { cpy := &ArbitrumUnsignedTx{ - ChainId: new(big.Int), - Nonce: tx.Nonce, - GasPrice: new(big.Int), - Gas: tx.Gas, - To: nil, - Value: new(big.Int), - Data: common.CopyBytes(tx.Data), + ChainId: new(big.Int), + Nonce: tx.Nonce, + GasPrice: new(big.Int), + Gas: tx.Gas, + To: nil, + Value: new(big.Int), + Data: common.CopyBytes(tx.Data), } if tx.ChainId != nil { cpy.ChainId.Set(tx.ChainId) @@ -63,7 +62,7 @@ func (tx *ArbitrumUnsignedTx) gasFeeCap() *big.Int { return tx.GasPrice } func (tx *ArbitrumUnsignedTx) value() *big.Int { return tx.Value } func (tx *ArbitrumUnsignedTx) nonce() uint64 { return tx.Nonce } func (tx *ArbitrumUnsignedTx) to() *common.Address { return tx.To } -func (tx *ArbitrumUnsignedTx) isFake() bool { return false } +func (tx *ArbitrumUnsignedTx) isFake() bool { return false } func (tx *ArbitrumUnsignedTx) rawSignatureValues() (v, r, s *big.Int) { return bigZero, bigZero, bigZero @@ -74,9 +73,9 @@ func (tx *ArbitrumUnsignedTx) setSignatureValues(chainID, v, r, s *big.Int) { } type ArbitrumContractTx struct { - ChainId *big.Int + ChainId *big.Int RequestId common.Hash - From common.Address + From common.Address GasPrice *big.Int // wei per gas Gas uint64 // gas limit @@ -85,7 +84,6 @@ type ArbitrumContractTx struct { Data []byte // contract invocation input data } - func (tx *ArbitrumContractTx) txType() byte { return ArbitrumContractTxType } func (tx *ArbitrumContractTx) copy() TxData { @@ -128,24 +126,24 @@ func (tx *ArbitrumContractTx) rawSignatureValues() (v, r, s *big.Int) { return bigZero, bigZero, bigZero } func (tx *ArbitrumContractTx) setSignatureValues(chainID, v, r, s *big.Int) {} -func (tx *ArbitrumContractTx) isFake() bool { return true } +func (tx *ArbitrumContractTx) isFake() bool { return true } -type DepositTx struct { - ChainId *big.Int +type ArbitrumDepositTx struct { + ChainId *big.Int L1RequestId common.Hash - To common.Address - Value *big.Int + To common.Address + Value *big.Int } -func (d *DepositTx) txType() byte { +func (d *ArbitrumDepositTx) txType() byte { return ArbitrumDepositTxType } -func (d *DepositTx) copy() TxData { - tx := &DepositTx{ +func (d *ArbitrumDepositTx) copy() TxData { + tx := &ArbitrumDepositTx{ ChainId: new(big.Int), - To: d.To, - Value: new(big.Int), + To: d.To, + Value: new(big.Int), } if d.ChainId != nil { tx.ChainId.Set(d.ChainId) @@ -156,23 +154,35 @@ func (d *DepositTx) copy() TxData { return tx } -func (d *DepositTx) chainID() *big.Int { return d.ChainId } -func (d *DepositTx) accessList() AccessList { return nil } -func (d *DepositTx) data() []byte { return nil } -func (d DepositTx) gas() uint64 { return 0 } -func (d *DepositTx) gasPrice() *big.Int { return bigZero } -func (d *DepositTx) gasTipCap() *big.Int { return bigZero } -func (d *DepositTx) gasFeeCap() *big.Int { return bigZero } -func (d *DepositTx) value() *big.Int { return d.Value } -func (d *DepositTx) nonce() uint64 { return 0 } -func (d *DepositTx) to() *common.Address { return &d.To } -func (d *DepositTx) isFake() bool { return true } - -func (d *DepositTx) rawSignatureValues() (v, r, s *big.Int) { +func (d *ArbitrumDepositTx) chainID() *big.Int { return d.ChainId } +func (d *ArbitrumDepositTx) accessList() AccessList { return nil } +func (d *ArbitrumDepositTx) data() []byte { return nil } +func (d ArbitrumDepositTx) gas() uint64 { return 0 } +func (d *ArbitrumDepositTx) gasPrice() *big.Int { return bigZero } +func (d *ArbitrumDepositTx) gasTipCap() *big.Int { return bigZero } +func (d *ArbitrumDepositTx) gasFeeCap() *big.Int { return bigZero } +func (d *ArbitrumDepositTx) value() *big.Int { return d.Value } +func (d *ArbitrumDepositTx) nonce() uint64 { return 0 } +func (d *ArbitrumDepositTx) to() *common.Address { return &d.To } +func (d *ArbitrumDepositTx) isFake() bool { return true } + +func (d *ArbitrumDepositTx) rawSignatureValues() (v, r, s *big.Int) { return bigZero, bigZero, bigZero } -func (d *DepositTx) setSignatureValues(chainID, v, r, s *big.Int) { +func (d *ArbitrumDepositTx) setSignatureValues(chainID, v, r, s *big.Int) { + +} +type ArbitrumWrappedTx struct { + l1Calldata uint64 + TxData } +func (tx *ArbitrumWrappedTx) copy() TxData { + cpy := &ArbitrumWrappedTx{ + l1Calldata: tx.l1Calldata, + TxData: tx.TxData.copy(), + } + return cpy +} diff --git a/core/types/arbitrum_signer.go b/core/types/arbitrum_signer.go index 5754af688846..d9cf4a057782 100644 --- a/core/types/arbitrum_signer.go +++ b/core/types/arbitrum_signer.go @@ -8,7 +8,7 @@ import ( var arbAddress = common.HexToAddress("0xabc") -type arbitrumSigner struct { Signer } +type arbitrumSigner struct{ Signer } func NewArbitrumSigner(signer Signer) Signer { return arbitrumSigner{Signer: signer} @@ -20,7 +20,7 @@ func (s arbitrumSigner) Sender(tx *Transaction) (common.Address, error) { return inner.From, nil case *ArbitrumContractTx: return inner.From, nil - case *DepositTx: + case *ArbitrumDepositTx: return arbAddress, nil default: return s.Signer.Sender(tx) @@ -38,7 +38,7 @@ func (s arbitrumSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *b return bigZero, bigZero, bigZero, nil case *ArbitrumContractTx: return bigZero, bigZero, bigZero, nil - case *DepositTx: + case *ArbitrumDepositTx: return bigZero, bigZero, bigZero, nil default: return s.Signer.SignatureValues(tx, sig) diff --git a/core/types/transaction.go b/core/types/transaction.go index 600e06c5a65d..0271ee4946b3 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -48,6 +48,7 @@ const ( ArbitrumDepositTxType = 200 ArbitrumUnsignedTxType = 201 ArbitrumContractTxType = 202 + ArbitrumWrappedTxType = 203 ) // Transaction is an Ethereum transaction. @@ -94,7 +95,7 @@ type TxData interface { // EncodeRLP implements rlp.Encoder func (tx *Transaction) EncodeRLP(w io.Writer) error { - if tx.Type() == LegacyTxType { + if tx.realType() == LegacyTxType { return rlp.Encode(w, tx.inner) } // It's an EIP-2718 typed TX envelope. @@ -109,7 +110,7 @@ func (tx *Transaction) EncodeRLP(w io.Writer) error { // encodeTyped writes the canonical encoding of a typed transaction to w. func (tx *Transaction) encodeTyped(w *bytes.Buffer) error { - w.WriteByte(tx.Type()) + w.WriteByte(tx.realType()) return rlp.Encode(w, tx.inner) } @@ -145,7 +146,7 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error { if b, err = s.Bytes(); err != nil { return err } - inner, err := tx.decodeTyped(b) + inner, err := tx.decodeTyped(b, true) if err == nil { tx.setDecoded(inner, len(b)) } @@ -169,7 +170,7 @@ func (tx *Transaction) UnmarshalBinary(b []byte) error { return nil } // It's an EIP2718 typed transaction envelope. - inner, err := tx.decodeTyped(b) + inner, err := tx.decodeTyped(b, false) if err != nil { return err } @@ -178,10 +179,30 @@ func (tx *Transaction) UnmarshalBinary(b []byte) error { } // decodeTyped decodes a typed transaction from the canonical format. -func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { +func (tx *Transaction) decodeTyped(b []byte, arbParsing bool) (TxData, error) { if len(b) == 0 { return nil, errEmptyTypedTx } + if arbParsing { + switch b[0] { + case ArbitrumDepositTxType: + var inner ArbitrumDepositTx + err := rlp.DecodeBytes(b[1:], &inner) + return &inner, err + case ArbitrumUnsignedTxType: + var inner ArbitrumUnsignedTx + err := rlp.DecodeBytes(b[1:], &inner) + return &inner, err + case ArbitrumContractTxType: + var inner ArbitrumContractTx + err := rlp.DecodeBytes(b[1:], &inner) + return &inner, err + case ArbitrumWrappedTxType: + var inner ArbitrumWrappedTx + err := rlp.DecodeBytes(b[1:], &inner) + return &inner, err + } + } switch b[0] { case AccessListTxType: var inner AccessListTx @@ -255,6 +276,19 @@ func (tx *Transaction) Type() uint8 { return tx.inner.txType() } +func (tx *Transaction) realType() uint8 { + _, isArbWrapped := tx.inner.(*ArbitrumWrappedTx) + if isArbWrapped { + return ArbitrumWrappedTxType + } else { + return tx.Type() + } +} + +func (tx *Transaction) GetInner() TxData { + return tx.inner.copy() +} + // ChainId returns the EIP155 chain ID of the transaction. The return value will always be // non-nil. For legacy transactions which are not replay-protected, the return value is // zero. diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 05bc7dd11811..073a1e7907a3 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -64,7 +64,7 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { // // Use this in transaction-handling code where the current block number is unknown. If you // have the current block number available, use MakeSigner instead. -func LatestSigner(config *params.ChainConfig) Signer { +func latestSignerImpl(config *params.ChainConfig) Signer { if config.ChainID != nil { if config.LondonBlock != nil { return NewLondonSigner(config.ChainID) @@ -79,6 +79,10 @@ func LatestSigner(config *params.ChainConfig) Signer { return HomesteadSigner{} } +func LatestSigner(config *params.ChainConfig) Signer { + return NewArbitrumSigner(latestSignerImpl(config)) +} + // LatestSignerForChainID returns the 'most permissive' Signer available. Specifically, // this enables support for EIP-155 replay protection and all implemented EIP-2718 // transaction types if chainID is non-nil. @@ -86,13 +90,17 @@ func LatestSigner(config *params.ChainConfig) Signer { // Use this in transaction-handling code where the current block number and fork // configuration are unknown. If you have a ChainConfig, use LatestSigner instead. // If you have a ChainConfig and know the current block number, use MakeSigner instead. -func LatestSignerForChainID(chainID *big.Int) Signer { +func latestSignerForChainIDImpl(chainID *big.Int) Signer { if chainID == nil { return HomesteadSigner{} } return NewLondonSigner(chainID) } +func LatestSignerForChainID(chainID *big.Int) Signer { + return NewArbitrumSigner(latestSignerForChainIDImpl(chainID)) +} + // SignTx signs the transaction using the given signer and private key. func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) { h := s.Hash(tx)