Skip to content

Expand custom Arbitrum tx types #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 48 additions & 38 deletions core/types/arb_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
Expand All @@ -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
}
6 changes: 3 additions & 3 deletions core/types/arbitrum_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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)
Expand All @@ -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)
Expand Down
44 changes: 39 additions & 5 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const (
ArbitrumDepositTxType = 200
ArbitrumUnsignedTxType = 201
ArbitrumContractTxType = 202
ArbitrumWrappedTxType = 203
)

// Transaction is an Ethereum transaction.
Expand Down Expand Up @@ -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.
Expand All @@ -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)
}

Expand Down Expand Up @@ -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))
}
Expand All @@ -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
}
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand Down
12 changes: 10 additions & 2 deletions core/types/transaction_signing.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -79,20 +79,28 @@ func LatestSigner(config *params.ChainConfig) Signer {
return HomesteadSigner{}
}

func LatestSigner(config *params.ChainConfig) Signer {
return NewArbitrumSigner(latestSignerImpl(config))
Copy link
Contributor

@hkalodner hkalodner Oct 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on this vs

signer := latestSignerImpl(config)
if config.IsArbitrum(blockNumber) {
	return NewArbitrumSigner(signer)
}
return signer

like in MakeSigner?

}

// 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.
//
// 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)
Expand Down