github.com/googgoog/go-ethereum@v1.9.7/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 "bytes" 21 "context" 22 "math/big" 23 "strings" 24 "testing" 25 26 "github.com/ethereum/go-ethereum" 27 "github.com/ethereum/go-ethereum/accounts/abi" 28 "github.com/ethereum/go-ethereum/accounts/abi/bind" 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/common/hexutil" 31 "github.com/ethereum/go-ethereum/core/types" 32 "github.com/ethereum/go-ethereum/crypto" 33 "github.com/ethereum/go-ethereum/rlp" 34 ) 35 36 type mockCaller struct { 37 codeAtBlockNumber *big.Int 38 callContractBlockNumber *big.Int 39 } 40 41 func (mc *mockCaller) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { 42 mc.codeAtBlockNumber = blockNumber 43 return []byte{1, 2, 3}, nil 44 } 45 46 func (mc *mockCaller) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { 47 mc.callContractBlockNumber = blockNumber 48 return nil, nil 49 } 50 func TestPassingBlockNumber(t *testing.T) { 51 52 mc := &mockCaller{} 53 54 bc := bind.NewBoundContract(common.HexToAddress("0x0"), abi.ABI{ 55 Methods: map[string]abi.Method{ 56 "something": { 57 Name: "something", 58 Outputs: abi.Arguments{}, 59 }, 60 }, 61 }, mc, nil, nil) 62 var ret string 63 64 blockNumber := big.NewInt(42) 65 66 bc.Call(&bind.CallOpts{BlockNumber: blockNumber}, &ret, "something") 67 68 if mc.callContractBlockNumber != blockNumber { 69 t.Fatalf("CallContract() was not passed the block number") 70 } 71 72 if mc.codeAtBlockNumber != blockNumber { 73 t.Fatalf("CodeAt() was not passed the block number") 74 } 75 76 bc.Call(&bind.CallOpts{}, &ret, "something") 77 78 if mc.callContractBlockNumber != nil { 79 t.Fatalf("CallContract() was passed a block number when it should not have been") 80 } 81 82 if mc.codeAtBlockNumber != nil { 83 t.Fatalf("CodeAt() was passed a block number when it should not have been") 84 } 85 } 86 87 const hexData = "0x000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158" 88 89 func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { 90 hash := crypto.Keccak256Hash([]byte("testName")) 91 mockLog := types.Log{ 92 Address: common.HexToAddress("0x0"), 93 Topics: []common.Hash{ 94 common.HexToHash("0x0"), 95 hash, 96 }, 97 Data: hexutil.MustDecode(hexData), 98 BlockNumber: uint64(26), 99 TxHash: common.HexToHash("0x0"), 100 TxIndex: 111, 101 BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), 102 Index: 7, 103 Removed: false, 104 } 105 106 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"}]` 107 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 108 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 109 110 receivedMap := make(map[string]interface{}) 111 expectedReceivedMap := map[string]interface{}{ 112 "name": hash, 113 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 114 "amount": big.NewInt(1), 115 "memo": []byte{88}, 116 } 117 if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil { 118 t.Error(err) 119 } 120 121 if len(receivedMap) != 4 { 122 t.Fatal("unpacked map expected to have length 4") 123 } 124 if receivedMap["name"] != expectedReceivedMap["name"] { 125 t.Error("unpacked map does not match expected map") 126 } 127 if receivedMap["sender"] != expectedReceivedMap["sender"] { 128 t.Error("unpacked map does not match expected map") 129 } 130 if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 { 131 t.Error("unpacked map does not match expected map") 132 } 133 if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) { 134 t.Error("unpacked map does not match expected map") 135 } 136 } 137 138 func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { 139 sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"}) 140 if err != nil { 141 t.Fatal(err) 142 } 143 hash := crypto.Keccak256Hash(sliceBytes) 144 mockLog := types.Log{ 145 Address: common.HexToAddress("0x0"), 146 Topics: []common.Hash{ 147 common.HexToHash("0x0"), 148 hash, 149 }, 150 Data: hexutil.MustDecode(hexData), 151 BlockNumber: uint64(26), 152 TxHash: common.HexToHash("0x0"), 153 TxIndex: 111, 154 BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), 155 Index: 7, 156 Removed: false, 157 } 158 159 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"}]` 160 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 161 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 162 163 receivedMap := make(map[string]interface{}) 164 expectedReceivedMap := map[string]interface{}{ 165 "names": hash, 166 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 167 "amount": big.NewInt(1), 168 "memo": []byte{88}, 169 } 170 if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil { 171 t.Error(err) 172 } 173 174 if len(receivedMap) != 4 { 175 t.Fatal("unpacked map expected to have length 4") 176 } 177 if receivedMap["names"] != expectedReceivedMap["names"] { 178 t.Error("unpacked map does not match expected map") 179 } 180 if receivedMap["sender"] != expectedReceivedMap["sender"] { 181 t.Error("unpacked map does not match expected map") 182 } 183 if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 { 184 t.Error("unpacked map does not match expected map") 185 } 186 if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) { 187 t.Error("unpacked map does not match expected map") 188 } 189 } 190 191 func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) { 192 arrBytes, err := rlp.EncodeToBytes([2]common.Address{common.HexToAddress("0x0"), common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2")}) 193 if err != nil { 194 t.Fatal(err) 195 } 196 hash := crypto.Keccak256Hash(arrBytes) 197 mockLog := types.Log{ 198 Address: common.HexToAddress("0x0"), 199 Topics: []common.Hash{ 200 common.HexToHash("0x0"), 201 hash, 202 }, 203 Data: hexutil.MustDecode(hexData), 204 BlockNumber: uint64(26), 205 TxHash: common.HexToHash("0x0"), 206 TxIndex: 111, 207 BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), 208 Index: 7, 209 Removed: false, 210 } 211 212 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"}]` 213 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 214 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 215 216 receivedMap := make(map[string]interface{}) 217 expectedReceivedMap := map[string]interface{}{ 218 "addresses": hash, 219 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 220 "amount": big.NewInt(1), 221 "memo": []byte{88}, 222 } 223 if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil { 224 t.Error(err) 225 } 226 227 if len(receivedMap) != 4 { 228 t.Fatal("unpacked map expected to have length 4") 229 } 230 if receivedMap["addresses"] != expectedReceivedMap["addresses"] { 231 t.Error("unpacked map does not match expected map") 232 } 233 if receivedMap["sender"] != expectedReceivedMap["sender"] { 234 t.Error("unpacked map does not match expected map") 235 } 236 if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 { 237 t.Error("unpacked map does not match expected map") 238 } 239 if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) { 240 t.Error("unpacked map does not match expected map") 241 } 242 } 243 244 func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) { 245 mockAddress := common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2") 246 addrBytes := mockAddress.Bytes() 247 hash := crypto.Keccak256Hash([]byte("mockFunction(address,uint)")) 248 functionSelector := hash[:4] 249 functionTyBytes := append(addrBytes, functionSelector...) 250 var functionTy [24]byte 251 copy(functionTy[:], functionTyBytes[0:24]) 252 mockLog := types.Log{ 253 Address: common.HexToAddress("0x0"), 254 Topics: []common.Hash{ 255 common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"), 256 common.BytesToHash(functionTyBytes), 257 }, 258 Data: hexutil.MustDecode(hexData), 259 BlockNumber: uint64(26), 260 TxHash: common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"), 261 TxIndex: 111, 262 BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), 263 Index: 7, 264 Removed: false, 265 } 266 267 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"}]` 268 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 269 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 270 271 receivedMap := make(map[string]interface{}) 272 expectedReceivedMap := map[string]interface{}{ 273 "function": functionTy, 274 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 275 "amount": big.NewInt(1), 276 "memo": []byte{88}, 277 } 278 if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil { 279 t.Error(err) 280 } 281 282 if len(receivedMap) != 4 { 283 t.Fatal("unpacked map expected to have length 4") 284 } 285 if receivedMap["function"] != expectedReceivedMap["function"] { 286 t.Error("unpacked map does not match expected map") 287 } 288 if receivedMap["sender"] != expectedReceivedMap["sender"] { 289 t.Error("unpacked map does not match expected map") 290 } 291 if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 { 292 t.Error("unpacked map does not match expected map") 293 } 294 if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) { 295 t.Error("unpacked map does not match expected map") 296 } 297 } 298 299 func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) { 300 byts := []byte{1, 2, 3, 4, 5} 301 hash := crypto.Keccak256Hash(byts) 302 mockLog := types.Log{ 303 Address: common.HexToAddress("0x0"), 304 Topics: []common.Hash{ 305 common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"), 306 hash, 307 }, 308 Data: hexutil.MustDecode(hexData), 309 BlockNumber: uint64(26), 310 TxHash: common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"), 311 TxIndex: 111, 312 BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), 313 Index: 7, 314 Removed: false, 315 } 316 317 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"}]` 318 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 319 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 320 321 receivedMap := make(map[string]interface{}) 322 expectedReceivedMap := map[string]interface{}{ 323 "content": hash, 324 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 325 "amount": big.NewInt(1), 326 "memo": []byte{88}, 327 } 328 if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil { 329 t.Error(err) 330 } 331 332 if len(receivedMap) != 4 { 333 t.Fatal("unpacked map expected to have length 4") 334 } 335 if receivedMap["content"] != expectedReceivedMap["content"] { 336 t.Error("unpacked map does not match expected map") 337 } 338 if receivedMap["sender"] != expectedReceivedMap["sender"] { 339 t.Error("unpacked map does not match expected map") 340 } 341 if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 { 342 t.Error("unpacked map does not match expected map") 343 } 344 if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) { 345 t.Error("unpacked map does not match expected map") 346 } 347 }