github.com/Inphi/go-ethereum@v1.9.7/core/types/receipt_test.go (about)

     1  // Copyright 2019 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package types
    18  
    19  import (
    20  	"bytes"
    21  	"math"
    22  	"math/big"
    23  	"reflect"
    24  	"testing"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/crypto"
    28  	"github.com/ethereum/go-ethereum/params"
    29  	"github.com/ethereum/go-ethereum/rlp"
    30  )
    31  
    32  func TestLegacyReceiptDecoding(t *testing.T) {
    33  	tests := []struct {
    34  		name   string
    35  		encode func(*Receipt) ([]byte, error)
    36  	}{
    37  		{
    38  			"StoredReceiptRLP",
    39  			encodeAsStoredReceiptRLP,
    40  		},
    41  		{
    42  			"V4StoredReceiptRLP",
    43  			encodeAsV4StoredReceiptRLP,
    44  		},
    45  		{
    46  			"V3StoredReceiptRLP",
    47  			encodeAsV3StoredReceiptRLP,
    48  		},
    49  	}
    50  
    51  	tx := NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil)
    52  	receipt := &Receipt{
    53  		Status:            ReceiptStatusFailed,
    54  		CumulativeGasUsed: 1,
    55  		Logs: []*Log{
    56  			{
    57  				Address: common.BytesToAddress([]byte{0x11}),
    58  				Topics:  []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
    59  				Data:    []byte{0x01, 0x00, 0xff},
    60  			},
    61  			{
    62  				Address: common.BytesToAddress([]byte{0x01, 0x11}),
    63  				Topics:  []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
    64  				Data:    []byte{0x01, 0x00, 0xff},
    65  			},
    66  		},
    67  		TxHash:          tx.Hash(),
    68  		ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
    69  		GasUsed:         111111,
    70  	}
    71  	receipt.Bloom = CreateBloom(Receipts{receipt})
    72  
    73  	for _, tc := range tests {
    74  		t.Run(tc.name, func(t *testing.T) {
    75  			enc, err := tc.encode(receipt)
    76  			if err != nil {
    77  				t.Fatalf("Error encoding receipt: %v", err)
    78  			}
    79  			var dec ReceiptForStorage
    80  			if err := rlp.DecodeBytes(enc, &dec); err != nil {
    81  				t.Fatalf("Error decoding RLP receipt: %v", err)
    82  			}
    83  			// Check whether all consensus fields are correct.
    84  			if dec.Status != receipt.Status {
    85  				t.Fatalf("Receipt status mismatch, want %v, have %v", receipt.Status, dec.Status)
    86  			}
    87  			if dec.CumulativeGasUsed != receipt.CumulativeGasUsed {
    88  				t.Fatalf("Receipt CumulativeGasUsed mismatch, want %v, have %v", receipt.CumulativeGasUsed, dec.CumulativeGasUsed)
    89  			}
    90  			if dec.Bloom != receipt.Bloom {
    91  				t.Fatalf("Bloom data mismatch, want %v, have %v", receipt.Bloom, dec.Bloom)
    92  			}
    93  			if len(dec.Logs) != len(receipt.Logs) {
    94  				t.Fatalf("Receipt log number mismatch, want %v, have %v", len(receipt.Logs), len(dec.Logs))
    95  			}
    96  			for i := 0; i < len(dec.Logs); i++ {
    97  				if dec.Logs[i].Address != receipt.Logs[i].Address {
    98  					t.Fatalf("Receipt log %d address mismatch, want %v, have %v", i, receipt.Logs[i].Address, dec.Logs[i].Address)
    99  				}
   100  				if !reflect.DeepEqual(dec.Logs[i].Topics, receipt.Logs[i].Topics) {
   101  					t.Fatalf("Receipt log %d topics mismatch, want %v, have %v", i, receipt.Logs[i].Topics, dec.Logs[i].Topics)
   102  				}
   103  				if !bytes.Equal(dec.Logs[i].Data, receipt.Logs[i].Data) {
   104  					t.Fatalf("Receipt log %d data mismatch, want %v, have %v", i, receipt.Logs[i].Data, dec.Logs[i].Data)
   105  				}
   106  			}
   107  		})
   108  	}
   109  }
   110  
   111  func encodeAsStoredReceiptRLP(want *Receipt) ([]byte, error) {
   112  	stored := &storedReceiptRLP{
   113  		PostStateOrStatus: want.statusEncoding(),
   114  		CumulativeGasUsed: want.CumulativeGasUsed,
   115  		Logs:              make([]*LogForStorage, len(want.Logs)),
   116  	}
   117  	for i, log := range want.Logs {
   118  		stored.Logs[i] = (*LogForStorage)(log)
   119  	}
   120  	return rlp.EncodeToBytes(stored)
   121  }
   122  
   123  func encodeAsV4StoredReceiptRLP(want *Receipt) ([]byte, error) {
   124  	stored := &v4StoredReceiptRLP{
   125  		PostStateOrStatus: want.statusEncoding(),
   126  		CumulativeGasUsed: want.CumulativeGasUsed,
   127  		TxHash:            want.TxHash,
   128  		ContractAddress:   want.ContractAddress,
   129  		Logs:              make([]*LogForStorage, len(want.Logs)),
   130  		GasUsed:           want.GasUsed,
   131  	}
   132  	for i, log := range want.Logs {
   133  		stored.Logs[i] = (*LogForStorage)(log)
   134  	}
   135  	return rlp.EncodeToBytes(stored)
   136  }
   137  
   138  func encodeAsV3StoredReceiptRLP(want *Receipt) ([]byte, error) {
   139  	stored := &v3StoredReceiptRLP{
   140  		PostStateOrStatus: want.statusEncoding(),
   141  		CumulativeGasUsed: want.CumulativeGasUsed,
   142  		Bloom:             want.Bloom,
   143  		TxHash:            want.TxHash,
   144  		ContractAddress:   want.ContractAddress,
   145  		Logs:              make([]*LogForStorage, len(want.Logs)),
   146  		GasUsed:           want.GasUsed,
   147  	}
   148  	for i, log := range want.Logs {
   149  		stored.Logs[i] = (*LogForStorage)(log)
   150  	}
   151  	return rlp.EncodeToBytes(stored)
   152  }
   153  
   154  // Tests that receipt data can be correctly derived from the contextual infos
   155  func TestDeriveFields(t *testing.T) {
   156  	// Create a few transactions to have receipts for
   157  	txs := Transactions{
   158  		NewContractCreation(1, big.NewInt(1), 1, big.NewInt(1), nil),
   159  		NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil),
   160  	}
   161  	// Create the corresponding receipts
   162  	receipts := Receipts{
   163  		&Receipt{
   164  			Status:            ReceiptStatusFailed,
   165  			CumulativeGasUsed: 1,
   166  			Logs: []*Log{
   167  				{Address: common.BytesToAddress([]byte{0x11})},
   168  				{Address: common.BytesToAddress([]byte{0x01, 0x11})},
   169  			},
   170  			TxHash:          txs[0].Hash(),
   171  			ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
   172  			GasUsed:         1,
   173  		},
   174  		&Receipt{
   175  			PostState:         common.Hash{2}.Bytes(),
   176  			CumulativeGasUsed: 3,
   177  			Logs: []*Log{
   178  				{Address: common.BytesToAddress([]byte{0x22})},
   179  				{Address: common.BytesToAddress([]byte{0x02, 0x22})},
   180  			},
   181  			TxHash:          txs[1].Hash(),
   182  			ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
   183  			GasUsed:         2,
   184  		},
   185  	}
   186  	// Clear all the computed fields and re-derive them
   187  	number := big.NewInt(1)
   188  	hash := common.BytesToHash([]byte{0x03, 0x14})
   189  
   190  	clearComputedFieldsOnReceipts(t, receipts)
   191  	if err := receipts.DeriveFields(params.TestChainConfig, hash, number.Uint64(), txs); err != nil {
   192  		t.Fatalf("DeriveFields(...) = %v, want <nil>", err)
   193  	}
   194  	// Iterate over all the computed fields and check that they're correct
   195  	signer := MakeSigner(params.TestChainConfig, number)
   196  
   197  	logIndex := uint(0)
   198  	for i := range receipts {
   199  		if receipts[i].TxHash != txs[i].Hash() {
   200  			t.Errorf("receipts[%d].TxHash = %s, want %s", i, receipts[i].TxHash.String(), txs[i].Hash().String())
   201  		}
   202  		if receipts[i].BlockHash != hash {
   203  			t.Errorf("receipts[%d].BlockHash = %s, want %s", i, receipts[i].BlockHash.String(), hash.String())
   204  		}
   205  		if receipts[i].BlockNumber.Cmp(number) != 0 {
   206  			t.Errorf("receipts[%c].BlockNumber = %s, want %s", i, receipts[i].BlockNumber.String(), number.String())
   207  		}
   208  		if receipts[i].TransactionIndex != uint(i) {
   209  			t.Errorf("receipts[%d].TransactionIndex = %d, want %d", i, receipts[i].TransactionIndex, i)
   210  		}
   211  		if receipts[i].GasUsed != txs[i].Gas() {
   212  			t.Errorf("receipts[%d].GasUsed = %d, want %d", i, receipts[i].GasUsed, txs[i].Gas())
   213  		}
   214  		if txs[i].To() != nil && receipts[i].ContractAddress != (common.Address{}) {
   215  			t.Errorf("receipts[%d].ContractAddress = %s, want %s", i, receipts[i].ContractAddress.String(), (common.Address{}).String())
   216  		}
   217  		from, _ := Sender(signer, txs[i])
   218  		contractAddress := crypto.CreateAddress(from, txs[i].Nonce())
   219  		if txs[i].To() == nil && receipts[i].ContractAddress != contractAddress {
   220  			t.Errorf("receipts[%d].ContractAddress = %s, want %s", i, receipts[i].ContractAddress.String(), contractAddress.String())
   221  		}
   222  		for j := range receipts[i].Logs {
   223  			if receipts[i].Logs[j].BlockNumber != number.Uint64() {
   224  				t.Errorf("receipts[%d].Logs[%d].BlockNumber = %d, want %d", i, j, receipts[i].Logs[j].BlockNumber, number.Uint64())
   225  			}
   226  			if receipts[i].Logs[j].BlockHash != hash {
   227  				t.Errorf("receipts[%d].Logs[%d].BlockHash = %s, want %s", i, j, receipts[i].Logs[j].BlockHash.String(), hash.String())
   228  			}
   229  			if receipts[i].Logs[j].TxHash != txs[i].Hash() {
   230  				t.Errorf("receipts[%d].Logs[%d].TxHash = %s, want %s", i, j, receipts[i].Logs[j].TxHash.String(), txs[i].Hash().String())
   231  			}
   232  			if receipts[i].Logs[j].TxHash != txs[i].Hash() {
   233  				t.Errorf("receipts[%d].Logs[%d].TxHash = %s, want %s", i, j, receipts[i].Logs[j].TxHash.String(), txs[i].Hash().String())
   234  			}
   235  			if receipts[i].Logs[j].TxIndex != uint(i) {
   236  				t.Errorf("receipts[%d].Logs[%d].TransactionIndex = %d, want %d", i, j, receipts[i].Logs[j].TxIndex, i)
   237  			}
   238  			if receipts[i].Logs[j].Index != logIndex {
   239  				t.Errorf("receipts[%d].Logs[%d].Index = %d, want %d", i, j, receipts[i].Logs[j].Index, logIndex)
   240  			}
   241  			logIndex++
   242  		}
   243  	}
   244  }
   245  
   246  func clearComputedFieldsOnReceipts(t *testing.T, receipts Receipts) {
   247  	t.Helper()
   248  
   249  	for _, receipt := range receipts {
   250  		clearComputedFieldsOnReceipt(t, receipt)
   251  	}
   252  }
   253  
   254  func clearComputedFieldsOnReceipt(t *testing.T, receipt *Receipt) {
   255  	t.Helper()
   256  
   257  	receipt.TxHash = common.Hash{}
   258  	receipt.BlockHash = common.Hash{}
   259  	receipt.BlockNumber = big.NewInt(math.MaxUint32)
   260  	receipt.TransactionIndex = math.MaxUint32
   261  	receipt.ContractAddress = common.Address{}
   262  	receipt.GasUsed = 0
   263  
   264  	clearComputedFieldsOnLogs(t, receipt.Logs)
   265  }
   266  
   267  func clearComputedFieldsOnLogs(t *testing.T, logs []*Log) {
   268  	t.Helper()
   269  
   270  	for _, log := range logs {
   271  		clearComputedFieldsOnLog(t, log)
   272  	}
   273  }
   274  
   275  func clearComputedFieldsOnLog(t *testing.T, log *Log) {
   276  	t.Helper()
   277  
   278  	log.BlockNumber = math.MaxUint32
   279  	log.BlockHash = common.Hash{}
   280  	log.TxHash = common.Hash{}
   281  	log.TxIndex = math.MaxUint32
   282  	log.Index = math.MaxUint32
   283  }