github.com/snowblossomcoin/go-ethereum@v1.9.25/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 }