Skip to content

Commit

Permalink
core/types: add new sponsored transaction types
Browse files Browse the repository at this point in the history
This commit adds new sponsored transaction type 0x64 (100) following EIP-2718:
Typed Transaction Envelope. The new transaction type is the same as legacy with
additional expiredTime and payer's signature field.
  • Loading branch information
minh-bq committed Nov 2, 2023
1 parent ca0ae03 commit 445937e
Show file tree
Hide file tree
Showing 14 changed files with 826 additions and 199 deletions.
4 changes: 4 additions & 0 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,10 @@ func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
func (m callMsg) Data() []byte { return m.CallMsg.Data }
func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList }

// FIXME: support sponsored transaction in callMsg
func (m callMsg) Payer() common.Address { return m.CallMsg.From }
func (m callMsg) ExpiredTime() uint64 { return 0 }

// filterBackend implements filters.Backend to support filtering for logs without
// taking bloom-bits acceleration structures into account.
type filterBackend struct {
Expand Down
5 changes: 5 additions & 0 deletions core/types/access_list_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ func (tx *AccessListTx) gasFeeCap() *big.Int { return tx.GasPrice }
func (tx *AccessListTx) value() *big.Int { return tx.Value }
func (tx *AccessListTx) nonce() uint64 { return tx.Nonce }
func (tx *AccessListTx) to() *common.Address { return tx.To }
func (tx *AccessListTx) expiredTime() uint64 { return 0 }

func (tx *AccessListTx) rawPayerSignatureValues() (v, r, s *big.Int) {
return nil, nil, nil
}

func (tx *AccessListTx) rawSignatureValues() (v, r, s *big.Int) {
return tx.V, tx.R, tx.S
Expand Down
5 changes: 5 additions & 0 deletions core/types/dynamic_fee_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.GasFeeCap }
func (tx *DynamicFeeTx) value() *big.Int { return tx.Value }
func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce }
func (tx *DynamicFeeTx) to() *common.Address { return tx.To }
func (tx *DynamicFeeTx) expiredTime() uint64 { return 0 }

func (tx *DynamicFeeTx) rawPayerSignatureValues() (v, r, s *big.Int) {
return nil, nil, nil
}

func (tx *DynamicFeeTx) rawSignatureValues() (v, r, s *big.Int) {
return tx.V, tx.R, tx.S
Expand Down
5 changes: 5 additions & 0 deletions core/types/legacy_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ func (tx *LegacyTx) gasFeeCap() *big.Int { return tx.GasPrice }
func (tx *LegacyTx) value() *big.Int { return tx.Value }
func (tx *LegacyTx) nonce() uint64 { return tx.Nonce }
func (tx *LegacyTx) to() *common.Address { return tx.To }
func (tx *LegacyTx) expiredTime() uint64 { return 0 }

func (tx *LegacyTx) rawPayerSignatureValues() (v, r, s *big.Int) {
return nil, nil, nil
}

func (tx *LegacyTx) rawSignatureValues() (v, r, s *big.Int) {
return tx.V, tx.R, tx.S
Expand Down
11 changes: 4 additions & 7 deletions core/types/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
return errEmptyTypedReceipt
}
r.Type = b[0]
if r.Type == AccessListTxType || r.Type == DynamicFeeTxType {
if r.Type == AccessListTxType || r.Type == DynamicFeeTxType || r.Type == SponsoredTxType {
var dec receiptRLP
if err := rlp.DecodeBytes(b[1:], &dec); err != nil {
return err
Expand Down Expand Up @@ -228,7 +228,7 @@ func (r *Receipt) decodeTyped(b []byte) error {
return errEmptyTypedReceipt
}
switch b[0] {
case DynamicFeeTxType, AccessListTxType:
case DynamicFeeTxType, AccessListTxType, SponsoredTxType:
var data receiptRLP
err := rlp.DecodeBytes(b[1:], &data)
if err != nil {
Expand Down Expand Up @@ -391,11 +391,8 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
switch r.Type {
case LegacyTxType:
rlp.Encode(w, data)
case AccessListTxType:
w.WriteByte(AccessListTxType)
rlp.Encode(w, data)
case DynamicFeeTxType:
w.WriteByte(DynamicFeeTxType)
case AccessListTxType, DynamicFeeTxType, SponsoredTxType:
w.WriteByte(r.Type)
rlp.Encode(w, data)
default:
// For unsupported types, write nothing. Since this is for
Expand Down
47 changes: 47 additions & 0 deletions core/types/receipt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,23 @@ var (
},
Type: DynamicFeeTxType,
}
mikoReceipt = &Receipt{
Status: ReceiptStatusFailed,
CumulativeGasUsed: 1,
Logs: []*Log{
{
Address: common.BytesToAddress([]byte{0x11}),
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
Data: []byte{0x01, 0x00, 0xff},
},
{
Address: common.BytesToAddress([]byte{0x01, 0x11}),
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
Data: []byte{0x01, 0x00, 0xff},
},
},
Type: SponsoredTxType,
}
)

func TestDecodeEmptyTypedReceipt(t *testing.T) {
Expand Down Expand Up @@ -427,6 +444,25 @@ func TestReceiptMarshalBinary(t *testing.T) {
if !bytes.Equal(have, eip1559Want) {
t.Errorf("encoded RLP mismatch, got %x want %x", have, eip1559Want)
}

// Miko Receipt
buf.Reset()
mikoReceipt.Bloom = CreateBloom(Receipts{mikoReceipt})
have, err = mikoReceipt.MarshalBinary()
if err != nil {
t.Fatalf("marshal binary error: %v", err)
}
mikoReceipts := Receipts{mikoReceipt}
mikoReceipts.EncodeIndex(0, buf)
haveEncodeIndex = buf.Bytes()
if !bytes.Equal(have, haveEncodeIndex) {
t.Errorf("BinaryMarshal and EncodeIndex mismatch, got %x want %x", have, haveEncodeIndex)
}
mikoWant := common.FromHex("64f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
if !bytes.Equal(have, mikoWant) {
t.Errorf("encoded RLP mismatch, got %x want %x", have, mikoWant)
}

}

func TestReceiptUnmarshalBinary(t *testing.T) {
Expand Down Expand Up @@ -462,6 +498,17 @@ func TestReceiptUnmarshalBinary(t *testing.T) {
if !reflect.DeepEqual(got1559Receipt, eip1559Receipt) {
t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", got1559Receipt, eip1559Receipt)
}

// miko Receipt
mikoRctBinary := common.FromHex("64f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
gotMikoReceipt := new(Receipt)
if err := gotMikoReceipt.UnmarshalBinary(mikoRctBinary); err != nil {
t.Fatalf("unmarshal binary error: %v", err)
}
mikoReceipt.Bloom = CreateBloom(Receipts{mikoReceipt})
if !reflect.DeepEqual(gotMikoReceipt, mikoReceipt) {
t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", gotMikoReceipt, mikoReceipt)
}
}

func clearComputedFieldsOnReceipts(t *testing.T, receipts Receipts) {
Expand Down
99 changes: 99 additions & 0 deletions core/types/sponsored_tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package types

import (
"math/big"

"github.com/ethereum/go-ethereum/common"
)

type SponsoredTx struct {
ChainID *big.Int // destination chain ID
Nonce uint64 // nonce of sender account
GasTipCap *big.Int // maximum tip to the miner
GasFeeCap *big.Int // maximum gas fee want to pay
Gas uint64 // gas limit
To *common.Address `rlp:"nil"` // nil means contract creation
Value *big.Int // wei amount
Data []byte // contract invocation input data
ExpiredTime uint64 // the expired time of payer's signature
PayerV, PayerR, PayerS *big.Int // payer's signature values
V, R, S *big.Int // sender's signature values
}

func (tx *SponsoredTx) copy() TxData {
cpy := &SponsoredTx{
Nonce: tx.Nonce,
To: copyAddressPtr(tx.To),
Data: common.CopyBytes(tx.Data),
Gas: tx.Gas,
ExpiredTime: tx.ExpiredTime,
// These are initialized below.
ChainID: new(big.Int),
Value: new(big.Int),
GasTipCap: new(big.Int),
GasFeeCap: new(big.Int),
PayerV: new(big.Int),
PayerR: new(big.Int),
PayerS: new(big.Int),
V: new(big.Int),
R: new(big.Int),
S: new(big.Int),
}
if tx.ChainID != nil {
cpy.ChainID.Set(tx.ChainID)
}
if tx.Value != nil {
cpy.Value.Set(tx.Value)
}
if tx.GasTipCap != nil {
cpy.GasTipCap.Set(tx.GasTipCap)
}
if tx.GasFeeCap != nil {
cpy.GasFeeCap.Set(tx.GasFeeCap)
}
if tx.PayerV != nil {
cpy.PayerV.Set(tx.PayerV)
}
if tx.PayerR != nil {
cpy.PayerR.Set(tx.PayerR)
}
if tx.PayerS != nil {
cpy.PayerS.Set(tx.PayerS)
}
if tx.V != nil {
cpy.V.Set(tx.V)
}
if tx.R != nil {
cpy.R.Set(tx.R)
}
if tx.S != nil {
cpy.S.Set(tx.S)
}
return cpy
}

// accessors for innerTx.
func (tx *SponsoredTx) txType() byte { return SponsoredTxType }
func (tx *SponsoredTx) chainID() *big.Int { return tx.ChainID }
func (tx *SponsoredTx) accessList() AccessList { return nil }
func (tx *SponsoredTx) data() []byte { return tx.Data }
func (tx *SponsoredTx) gas() uint64 { return tx.Gas }
func (tx *SponsoredTx) gasPrice() *big.Int { return tx.GasFeeCap }
func (tx *SponsoredTx) gasTipCap() *big.Int { return tx.GasTipCap }
func (tx *SponsoredTx) gasFeeCap() *big.Int { return tx.GasFeeCap }
func (tx *SponsoredTx) value() *big.Int { return tx.Value }
func (tx *SponsoredTx) nonce() uint64 { return tx.Nonce }
func (tx *SponsoredTx) to() *common.Address { return tx.To }
func (tx *SponsoredTx) expiredTime() uint64 { return tx.ExpiredTime }

func (tx *SponsoredTx) rawPayerSignatureValues() (v, r, s *big.Int) {
return tx.PayerV, tx.PayerR, tx.PayerS
}

func (tx *SponsoredTx) rawSignatureValues() (v, r, s *big.Int) {
return tx.V, tx.R, tx.S
}

func (tx *SponsoredTx) setSignatureValues(chainID, v, r, s *big.Int) {
tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s
}
Loading

0 comments on commit 445937e

Please sign in to comment.