@ -18,15 +18,16 @@ package types
import (
"bytes"
"encoding/json"
"math"
"math/big"
"reflect"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/kylelemons/godebug/diff"
)
var (
@ -96,122 +97,177 @@ func TestDeriveFields(t *testing.T) {
// Create a few transactions to have receipts for
to2 := common . HexToAddress ( "0x2" )
to3 := common . HexToAddress ( "0x3" )
to4 := common . HexToAddress ( "0x4" )
to5 := common . HexToAddress ( "0x5" )
txs := Transactions {
NewTx ( & LegacyTx {
Nonce : 1 ,
Value : big . NewInt ( 1 ) ,
Gas : 1 ,
GasPrice : big . NewInt ( 1 ) ,
GasPrice : big . NewInt ( 11 ) ,
} ) ,
NewTx ( & LegacyTx {
To : & to2 ,
Nonce : 2 ,
Value : big . NewInt ( 2 ) ,
Gas : 2 ,
GasPrice : big . NewInt ( 2 ) ,
GasPrice : big . NewInt ( 22 ) ,
} ) ,
NewTx ( & AccessListTx {
To : & to3 ,
Nonce : 3 ,
Value : big . NewInt ( 3 ) ,
Gas : 3 ,
GasPrice : big . NewInt ( 3 ) ,
GasPrice : big . NewInt ( 33 ) ,
} ) ,
// EIP-1559 transactions.
NewTx ( & DynamicFeeTx {
To : & to4 ,
Nonce : 4 ,
Value : big . NewInt ( 4 ) ,
Gas : 4 ,
GasTipCap : big . NewInt ( 44 ) ,
GasFeeCap : big . NewInt ( 1045 ) ,
} ) ,
NewTx ( & DynamicFeeTx {
To : & to5 ,
Nonce : 5 ,
Value : big . NewInt ( 5 ) ,
Gas : 5 ,
GasTipCap : big . NewInt ( 56 ) ,
GasFeeCap : big . NewInt ( 1055 ) ,
} ) ,
}
blockNumber := big . NewInt ( 1 )
blockHash := common . BytesToHash ( [ ] byte { 0x03 , 0x14 } )
// Create the corresponding receipts
receipts := Receipts {
& Receipt {
Status : ReceiptStatusFailed ,
CumulativeGasUsed : 1 ,
Logs : [ ] * Log {
{ Address : common . BytesToAddress ( [ ] byte { 0x11 } ) } ,
{ Address : common . BytesToAddress ( [ ] byte { 0x01 , 0x11 } ) } ,
{
Address : common . BytesToAddress ( [ ] byte { 0x11 } ) ,
// derived fields:
BlockNumber : blockNumber . Uint64 ( ) ,
TxHash : txs [ 0 ] . Hash ( ) ,
TxIndex : 0 ,
BlockHash : blockHash ,
Index : 0 ,
} ,
{
Address : common . BytesToAddress ( [ ] byte { 0x01 , 0x11 } ) ,
// derived fields:
BlockNumber : blockNumber . Uint64 ( ) ,
TxHash : txs [ 0 ] . Hash ( ) ,
TxIndex : 0 ,
BlockHash : blockHash ,
Index : 1 ,
} ,
} ,
TxHash : txs [ 0 ] . Hash ( ) ,
ContractAddress : common . BytesToAddress ( [ ] byte { 0x01 , 0x11 , 0x11 } ) ,
GasUsed : 1 ,
// derived fields:
TxHash : txs [ 0 ] . Hash ( ) ,
ContractAddress : common . HexToAddress ( "0x5a443704dd4b594b382c22a083e2bd3090a6fef3" ) ,
GasUsed : 1 ,
EffectiveGasPrice : big . NewInt ( 11 ) ,
BlockHash : blockHash ,
BlockNumber : blockNumber ,
TransactionIndex : 0 ,
} ,
& Receipt {
PostState : common . Hash { 2 } . Bytes ( ) ,
CumulativeGasUsed : 3 ,
Logs : [ ] * Log {
{ Address : common . BytesToAddress ( [ ] byte { 0x22 } ) } ,
{ Address : common . BytesToAddress ( [ ] byte { 0x02 , 0x22 } ) } ,
{
Address : common . BytesToAddress ( [ ] byte { 0x22 } ) ,
// derived fields:
BlockNumber : blockNumber . Uint64 ( ) ,
TxHash : txs [ 1 ] . Hash ( ) ,
TxIndex : 1 ,
BlockHash : blockHash ,
Index : 2 ,
} ,
{
Address : common . BytesToAddress ( [ ] byte { 0x02 , 0x22 } ) ,
// derived fields:
BlockNumber : blockNumber . Uint64 ( ) ,
TxHash : txs [ 1 ] . Hash ( ) ,
TxIndex : 1 ,
BlockHash : blockHash ,
Index : 3 ,
} ,
} ,
TxHash : txs [ 1 ] . Hash ( ) ,
ContractAddress : common . BytesToAddress ( [ ] byte { 0x02 , 0x22 , 0x22 } ) ,
GasUsed : 2 ,
// derived fields:
TxHash : txs [ 1 ] . Hash ( ) ,
GasUsed : 2 ,
EffectiveGasPrice : big . NewInt ( 22 ) ,
BlockHash : blockHash ,
BlockNumber : blockNumber ,
TransactionIndex : 1 ,
} ,
& Receipt {
Type : AccessListTxType ,
PostState : common . Hash { 3 } . Bytes ( ) ,
CumulativeGasUsed : 6 ,
Logs : [ ] * Log {
{ Address : common . BytesToAddress ( [ ] byte { 0x33 } ) } ,
{ Address : common . BytesToAddress ( [ ] byte { 0x03 , 0x33 } ) } ,
} ,
TxHash : txs [ 2 ] . Hash ( ) ,
ContractAddress : common . BytesToAddress ( [ ] byte { 0x03 , 0x33 , 0x33 } ) ,
GasUsed : 3 ,
Logs : [ ] * Log { } ,
// derived fields:
TxHash : txs [ 2 ] . Hash ( ) ,
GasUsed : 3 ,
EffectiveGasPrice : big . NewInt ( 33 ) ,
BlockHash : blockHash ,
BlockNumber : blockNumber ,
TransactionIndex : 2 ,
} ,
& Receipt {
Type : DynamicFeeTxType ,
PostState : common . Hash { 4 } . Bytes ( ) ,
CumulativeGasUsed : 10 ,
Logs : [ ] * Log { } ,
// derived fields:
TxHash : txs [ 3 ] . Hash ( ) ,
GasUsed : 4 ,
EffectiveGasPrice : big . NewInt ( 1044 ) ,
BlockHash : blockHash ,
BlockNumber : blockNumber ,
TransactionIndex : 3 ,
} ,
& Receipt {
Type : DynamicFeeTxType ,
PostState : common . Hash { 5 } . Bytes ( ) ,
CumulativeGasUsed : 15 ,
Logs : [ ] * Log { } ,
// derived fields:
TxHash : txs [ 4 ] . Hash ( ) ,
GasUsed : 5 ,
EffectiveGasPrice : big . NewInt ( 1055 ) ,
BlockHash : blockHash ,
BlockNumber : blockNumber ,
TransactionIndex : 4 ,
} ,
}
// Clear all the computed fields and re-derive them
number := big . NewInt ( 1 )
hash := common . BytesToHash ( [ ] byte { 0x03 , 0x14 } )
clearComputedFieldsOnReceipts ( t , receipts )
if err := receipts . DeriveFields ( params . TestChainConfig , hash , number . Uint64 ( ) , txs ) ; err != nil {
// Re-derive receipts.
basefee := big . NewInt ( 1000 )
derivedReceipts := clearComputedFieldsOnReceipts ( receipts )
err := Receipts ( derivedReceipts ) . DeriveFields ( params . TestChainConfig , blockHash , blockNumber . Uint64 ( ) , basefee , txs )
if err != nil {
t . Fatalf ( "DeriveFields(...) = %v, want <nil>" , err )
}
// Iterate over all the computed fields and check that they're correct
signer := MakeSigner ( params . TestChainConfig , number )
logIndex := uint ( 0 )
for i := range receipts {
if receipts [ i ] . Type != txs [ i ] . Type ( ) {
t . Errorf ( "receipts[%d].Type = %d, want %d" , i , receipts [ i ] . Type , txs [ i ] . Type ( ) )
}
if receipts [ i ] . TxHash != txs [ i ] . Hash ( ) {
t . Errorf ( "receipts[%d].TxHash = %s, want %s" , i , receipts [ i ] . TxHash . String ( ) , txs [ i ] . Hash ( ) . String ( ) )
}
if receipts [ i ] . BlockHash != hash {
t . Errorf ( "receipts[%d].BlockHash = %s, want %s" , i , receipts [ i ] . BlockHash . String ( ) , hash . String ( ) )
}
if receipts [ i ] . BlockNumber . Cmp ( number ) != 0 {
t . Errorf ( "receipts[%c].BlockNumber = %s, want %s" , i , receipts [ i ] . BlockNumber . String ( ) , number . String ( ) )
}
if receipts [ i ] . TransactionIndex != uint ( i ) {
t . Errorf ( "receipts[%d].TransactionIndex = %d, want %d" , i , receipts [ i ] . TransactionIndex , i )
}
if receipts [ i ] . GasUsed != txs [ i ] . Gas ( ) {
t . Errorf ( "receipts[%d].GasUsed = %d, want %d" , i , receipts [ i ] . GasUsed , txs [ i ] . Gas ( ) )
}
if txs [ i ] . To ( ) != nil && receipts [ i ] . ContractAddress != ( common . Address { } ) {
t . Errorf ( "receipts[%d].ContractAddress = %s, want %s" , i , receipts [ i ] . ContractAddress . String ( ) , ( common . Address { } ) . String ( ) )
}
from , _ := Sender ( signer , txs [ i ] )
contractAddress := crypto . CreateAddress ( from , txs [ i ] . Nonce ( ) )
if txs [ i ] . To ( ) == nil && receipts [ i ] . ContractAddress != contractAddress {
t . Errorf ( "receipts[%d].ContractAddress = %s, want %s" , i , receipts [ i ] . ContractAddress . String ( ) , contractAddress . String ( ) )
}
for j := range receipts [ i ] . Logs {
if receipts [ i ] . Logs [ j ] . BlockNumber != number . Uint64 ( ) {
t . Errorf ( "receipts[%d].Logs[%d].BlockNumber = %d, want %d" , i , j , receipts [ i ] . Logs [ j ] . BlockNumber , number . Uint64 ( ) )
}
if receipts [ i ] . Logs [ j ] . BlockHash != hash {
t . Errorf ( "receipts[%d].Logs[%d].BlockHash = %s, want %s" , i , j , receipts [ i ] . Logs [ j ] . BlockHash . String ( ) , hash . String ( ) )
}
if receipts [ i ] . Logs [ j ] . TxHash != txs [ i ] . Hash ( ) {
t . Errorf ( "receipts[%d].Logs[%d].TxHash = %s, want %s" , i , j , receipts [ i ] . Logs [ j ] . TxHash . String ( ) , txs [ i ] . Hash ( ) . String ( ) )
}
if receipts [ i ] . Logs [ j ] . TxIndex != uint ( i ) {
t . Errorf ( "receipts[%d].Logs[%d].TransactionIndex = %d, want %d" , i , j , receipts [ i ] . Logs [ j ] . TxIndex , i )
}
if receipts [ i ] . Logs [ j ] . Index != logIndex {
t . Errorf ( "receipts[%d].Logs[%d].Index = %d, want %d" , i , j , receipts [ i ] . Logs [ j ] . Index , logIndex )
}
logIndex ++
}
// Check diff of receipts against derivedReceipts.
r1 , err := json . MarshalIndent ( receipts , "" , " " )
if err != nil {
t . Fatal ( "error marshaling input receipts:" , err )
}
r2 , err := json . MarshalIndent ( derivedReceipts , "" , " " )
if err != nil {
t . Fatal ( "error marshaling derived receipts:" , err )
}
d := diff . Diff ( string ( r1 ) , string ( r2 ) )
if d != "" {
t . Fatal ( "receipts differ:" , d )
}
}
@ -342,41 +398,36 @@ func TestReceiptUnmarshalBinary(t *testing.T) {
}
}
func clearComputedFieldsOnReceipts ( t * testing . T , receipts Receipts ) {
t . Helper ( )
for _ , receipt := range receipts {
clearComputedFieldsOnReceipt ( t , receipt )
func clearComputedFieldsOnReceipts ( receipts [ ] * Receipt ) [ ] * Receipt {
r := make ( [ ] * Receipt , len ( receipts ) )
for i , receipt := range receipts {
r [ i ] = clearComputedFieldsOnReceipt ( receipt )
}
return r
}
func clearComputedFieldsOnReceipt ( t * testing . T , receipt * Receipt ) {
t . Helper ( )
receipt . TxHash = common . Hash { }
receipt . BlockHash = common . Hash { }
receipt . BlockNumber = big . NewInt ( math . MaxUint32 )
receipt . TransactionIndex = math . MaxUint32
receipt . ContractAddress = common . Address { }
receipt . GasUsed = 0
clearComputedFieldsOnLogs ( t , receipt . Logs )
func clearComputedFieldsOnReceipt ( receipt * Receipt ) * Receipt {
cpy := * receipt
cpy . TxHash = common . Hash { 0xff , 0xff , 0x11 }
cpy . BlockHash = common . Hash { 0xff , 0xff , 0x22 }
cpy . BlockNumber = big . NewInt ( math . MaxUint32 )
cpy . TransactionIndex = math . MaxUint32
cpy . ContractAddress = common . Address { 0xff , 0xff , 0x33 }
cpy . GasUsed = 0xffffffff
cpy . Logs = clearComputedFieldsOnLogs ( receipt . Logs )
return & cpy
}
func clearComputedFieldsOnLogs ( t * testing . T , logs [ ] * Log ) {
t . Helper ( )
for _ , log := range logs {
clearComputedFieldsOnLog ( t , log )
func clearComputedFieldsOnLogs ( logs [ ] * Log ) [ ] * Log {
l := make ( [ ] * Log , len ( logs ) )
for i , log := range logs {
cpy := * log
cpy . BlockNumber = math . MaxUint32
cpy . BlockHash = common . Hash { }
cpy . TxHash = common . Hash { }
cpy . TxIndex = math . MaxUint32
cpy . Index = math . MaxUint32
l [ i ] = & cpy
}
}
func clearComputedFieldsOnLog ( t * testing . T , log * Log ) {
t . Helper ( )
log . BlockNumber = math . MaxUint32
log . BlockHash = common . Hash { }
log . TxHash = common . Hash { }
log . TxIndex = math . MaxUint32
log . Index = math . MaxUint32
return l
}