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