github.com/ethereum/go-ethereum@v1.16.1/tests/transaction_test_util.go (about) 1 // Copyright 2015 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 tests 18 19 import ( 20 "fmt" 21 "math/big" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/common/hexutil" 25 "github.com/ethereum/go-ethereum/common/math" 26 "github.com/ethereum/go-ethereum/core" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/params" 29 ) 30 31 // TransactionTest checks RLP decoding and sender derivation of transactions. 32 type TransactionTest struct { 33 Txbytes hexutil.Bytes `json:"txbytes"` 34 Result map[string]*ttFork 35 } 36 37 type ttFork struct { 38 Sender *common.UnprefixedAddress `json:"sender"` 39 Hash *common.UnprefixedHash `json:"hash"` 40 Exception *string `json:"exception"` 41 IntrinsicGas math.HexOrDecimal64 `json:"intrinsicGas"` 42 } 43 44 func (tt *TransactionTest) validate() error { 45 if tt.Txbytes == nil { 46 return fmt.Errorf("missing txbytes") 47 } 48 for name, fork := range tt.Result { 49 if err := tt.validateFork(fork); err != nil { 50 return fmt.Errorf("invalid %s: %v", name, err) 51 } 52 } 53 return nil 54 } 55 56 func (tt *TransactionTest) validateFork(fork *ttFork) error { 57 if fork == nil { 58 return nil 59 } 60 if fork.Hash == nil && fork.Exception == nil { 61 return fmt.Errorf("missing hash and exception") 62 } 63 if fork.Hash != nil && fork.Sender == nil { 64 return fmt.Errorf("missing sender") 65 } 66 return nil 67 } 68 69 func (tt *TransactionTest) Run() error { 70 if err := tt.validate(); err != nil { 71 return err 72 } 73 validateTx := func(rlpData hexutil.Bytes, signer types.Signer, rules *params.Rules) (sender common.Address, hash common.Hash, requiredGas uint64, err error) { 74 tx := new(types.Transaction) 75 if err = tx.UnmarshalBinary(rlpData); err != nil { 76 return 77 } 78 sender, err = types.Sender(signer, tx) 79 if err != nil { 80 return 81 } 82 // Intrinsic gas 83 requiredGas, err = core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) 84 if err != nil { 85 return 86 } 87 if requiredGas > tx.Gas() { 88 return sender, hash, 0, fmt.Errorf("insufficient gas ( %d < %d )", tx.Gas(), requiredGas) 89 } 90 91 if rules.IsPrague { 92 var floorDataGas uint64 93 floorDataGas, err = core.FloorDataGas(tx.Data()) 94 if err != nil { 95 return 96 } 97 if tx.Gas() < floorDataGas { 98 return sender, hash, 0, fmt.Errorf("%w: have %d, want %d", core.ErrFloorDataGas, tx.Gas(), floorDataGas) 99 } 100 } 101 hash = tx.Hash() 102 return sender, hash, requiredGas, nil 103 } 104 for _, testcase := range []struct { 105 name string 106 isMerge bool 107 }{ 108 {"Frontier", false}, 109 {"Homestead", false}, 110 {"EIP150", false}, 111 {"EIP158", false}, 112 {"Byzantium", false}, 113 {"Constantinople", false}, 114 {"Istanbul", false}, 115 {"Berlin", false}, 116 {"London", false}, 117 {"Paris", true}, 118 {"Shanghai", true}, 119 {"Cancun", true}, 120 {"Prague", true}, 121 } { 122 expected := tt.Result[testcase.name] 123 if expected == nil { 124 continue 125 } 126 config, ok := Forks[testcase.name] 127 if !ok || config == nil { 128 return UnsupportedForkError{Name: testcase.name} 129 } 130 var ( 131 rules = config.Rules(new(big.Int), testcase.isMerge, 0) 132 signer = types.MakeSigner(config, new(big.Int), 0) 133 ) 134 sender, hash, gas, err := validateTx(tt.Txbytes, signer, &rules) 135 if err != nil { 136 if expected.Hash != nil { 137 return fmt.Errorf("unexpected error fork %s: %v", testcase.name, err) 138 } 139 continue 140 } 141 if expected.Exception != nil { 142 return fmt.Errorf("expected error %v, got none (%v), fork %s", *expected.Exception, err, testcase.name) 143 } 144 if common.Hash(*expected.Hash) != hash { 145 return fmt.Errorf("hash mismatch: got %x, want %x", hash, common.Hash(*expected.Hash)) 146 } 147 if common.Address(*expected.Sender) != sender { 148 return fmt.Errorf("sender mismatch: got %x, want %x", sender, expected.Sender) 149 } 150 if uint64(expected.IntrinsicGas) != gas { 151 return fmt.Errorf("intrinsic gas mismatch: got %d, want %d", gas, uint64(expected.IntrinsicGas)) 152 } 153 } 154 return nil 155 }