github.com/zhiqiangxu/go-ethereum@v1.9.16-0.20210824055606-be91cfdebc48/accounts/abi/bind/base_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 bind_test 18 19 import ( 20 "context" 21 "math/big" 22 "reflect" 23 "strings" 24 "testing" 25 26 "github.com/zhiqiangxu/go-ethereum" 27 "github.com/zhiqiangxu/go-ethereum/accounts/abi" 28 "github.com/zhiqiangxu/go-ethereum/accounts/abi/bind" 29 "github.com/zhiqiangxu/go-ethereum/common" 30 "github.com/zhiqiangxu/go-ethereum/common/hexutil" 31 "github.com/zhiqiangxu/go-ethereum/core/types" 32 "github.com/zhiqiangxu/go-ethereum/crypto" 33 "github.com/zhiqiangxu/go-ethereum/rlp" 34 ) 35 36 type mockCaller struct { 37 codeAtBlockNumber *big.Int 38 callContractBlockNumber *big.Int 39 pendingCodeAtCalled bool 40 pendingCallContractCalled bool 41 } 42 43 func (mc *mockCaller) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { 44 mc.codeAtBlockNumber = blockNumber 45 return []byte{1, 2, 3}, nil 46 } 47 48 func (mc *mockCaller) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { 49 mc.callContractBlockNumber = blockNumber 50 return nil, nil 51 } 52 53 func (mc *mockCaller) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) { 54 mc.pendingCodeAtCalled = true 55 return nil, nil 56 } 57 58 func (mc *mockCaller) PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error) { 59 mc.pendingCallContractCalled = true 60 return nil, nil 61 } 62 func TestPassingBlockNumber(t *testing.T) { 63 64 mc := &mockCaller{} 65 66 bc := bind.NewBoundContract(common.HexToAddress("0x0"), abi.ABI{ 67 Methods: map[string]abi.Method{ 68 "something": { 69 Name: "something", 70 Outputs: abi.Arguments{}, 71 }, 72 }, 73 }, mc, nil, nil) 74 var ret string 75 76 blockNumber := big.NewInt(42) 77 78 bc.Call(&bind.CallOpts{BlockNumber: blockNumber}, &ret, "something") 79 80 if mc.callContractBlockNumber != blockNumber { 81 t.Fatalf("CallContract() was not passed the block number") 82 } 83 84 if mc.codeAtBlockNumber != blockNumber { 85 t.Fatalf("CodeAt() was not passed the block number") 86 } 87 88 bc.Call(&bind.CallOpts{}, &ret, "something") 89 90 if mc.callContractBlockNumber != nil { 91 t.Fatalf("CallContract() was passed a block number when it should not have been") 92 } 93 94 if mc.codeAtBlockNumber != nil { 95 t.Fatalf("CodeAt() was passed a block number when it should not have been") 96 } 97 98 bc.Call(&bind.CallOpts{BlockNumber: blockNumber, Pending: true}, &ret, "something") 99 100 if !mc.pendingCallContractCalled { 101 t.Fatalf("CallContract() was not passed the block number") 102 } 103 104 if !mc.pendingCodeAtCalled { 105 t.Fatalf("CodeAt() was not passed the block number") 106 } 107 } 108 109 const hexData = "0x000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158" 110 111 func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { 112 hash := crypto.Keccak256Hash([]byte("testName")) 113 topics := []common.Hash{ 114 common.HexToHash("0x0"), 115 hash, 116 } 117 mockLog := newMockLog(topics, common.HexToHash("0x0")) 118 119 abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"string"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` 120 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 121 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 122 123 expectedReceivedMap := map[string]interface{}{ 124 "name": hash, 125 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 126 "amount": big.NewInt(1), 127 "memo": []byte{88}, 128 } 129 unpackAndCheck(t, bc, expectedReceivedMap, mockLog) 130 } 131 132 func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { 133 sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"}) 134 if err != nil { 135 t.Fatal(err) 136 } 137 hash := crypto.Keccak256Hash(sliceBytes) 138 topics := []common.Hash{ 139 common.HexToHash("0x0"), 140 hash, 141 } 142 mockLog := newMockLog(topics, common.HexToHash("0x0")) 143 144 abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"names","type":"string[]"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` 145 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 146 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 147 148 expectedReceivedMap := map[string]interface{}{ 149 "names": hash, 150 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 151 "amount": big.NewInt(1), 152 "memo": []byte{88}, 153 } 154 unpackAndCheck(t, bc, expectedReceivedMap, mockLog) 155 } 156 157 func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) { 158 arrBytes, err := rlp.EncodeToBytes([2]common.Address{common.HexToAddress("0x0"), common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2")}) 159 if err != nil { 160 t.Fatal(err) 161 } 162 hash := crypto.Keccak256Hash(arrBytes) 163 topics := []common.Hash{ 164 common.HexToHash("0x0"), 165 hash, 166 } 167 mockLog := newMockLog(topics, common.HexToHash("0x0")) 168 169 abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"addresses","type":"address[2]"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` 170 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 171 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 172 173 expectedReceivedMap := map[string]interface{}{ 174 "addresses": hash, 175 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 176 "amount": big.NewInt(1), 177 "memo": []byte{88}, 178 } 179 unpackAndCheck(t, bc, expectedReceivedMap, mockLog) 180 } 181 182 func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) { 183 mockAddress := common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2") 184 addrBytes := mockAddress.Bytes() 185 hash := crypto.Keccak256Hash([]byte("mockFunction(address,uint)")) 186 functionSelector := hash[:4] 187 functionTyBytes := append(addrBytes, functionSelector...) 188 var functionTy [24]byte 189 copy(functionTy[:], functionTyBytes[0:24]) 190 topics := []common.Hash{ 191 common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"), 192 common.BytesToHash(functionTyBytes), 193 } 194 mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42")) 195 abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"function","type":"function"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` 196 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 197 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 198 199 expectedReceivedMap := map[string]interface{}{ 200 "function": functionTy, 201 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 202 "amount": big.NewInt(1), 203 "memo": []byte{88}, 204 } 205 unpackAndCheck(t, bc, expectedReceivedMap, mockLog) 206 } 207 208 func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) { 209 bytes := []byte{1, 2, 3, 4, 5} 210 hash := crypto.Keccak256Hash(bytes) 211 topics := []common.Hash{ 212 common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"), 213 hash, 214 } 215 mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42")) 216 217 abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"content","type":"bytes"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` 218 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 219 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 220 221 expectedReceivedMap := map[string]interface{}{ 222 "content": hash, 223 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 224 "amount": big.NewInt(1), 225 "memo": []byte{88}, 226 } 227 unpackAndCheck(t, bc, expectedReceivedMap, mockLog) 228 } 229 230 func unpackAndCheck(t *testing.T, bc *bind.BoundContract, expected map[string]interface{}, mockLog types.Log) { 231 received := make(map[string]interface{}) 232 if err := bc.UnpackLogIntoMap(received, "received", mockLog); err != nil { 233 t.Error(err) 234 } 235 236 if len(received) != len(expected) { 237 t.Fatalf("unpacked map length %v not equal expected length of %v", len(received), len(expected)) 238 } 239 for name, elem := range expected { 240 if !reflect.DeepEqual(elem, received[name]) { 241 t.Errorf("field %v does not match expected, want %v, got %v", name, elem, received[name]) 242 } 243 } 244 } 245 246 func newMockLog(topics []common.Hash, txHash common.Hash) types.Log { 247 return types.Log{ 248 Address: common.HexToAddress("0x0"), 249 Topics: topics, 250 Data: hexutil.MustDecode(hexData), 251 BlockNumber: uint64(26), 252 TxHash: txHash, 253 TxIndex: 111, 254 BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), 255 Index: 7, 256 Removed: false, 257 } 258 }