github.com/klaytn/klaytn@v1.12.1/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 79 blockNumber := big.NewInt(42) 80 81 bc.Call(&bind.CallOpts{BlockNumber: blockNumber}, nil, "something") 82 83 if mc.callContractBlockNumber != blockNumber { 84 t.Fatalf("CallContract() was not passed the block number") 85 } 86 87 if mc.codeAtBlockNumber != blockNumber { 88 t.Fatalf("CodeAt() was not passed the block number") 89 } 90 91 bc.Call(&bind.CallOpts{}, nil, "something") 92 93 if mc.callContractBlockNumber != nil { 94 t.Fatalf("CallContract() was passed a block number when it should not have been") 95 } 96 97 if mc.codeAtBlockNumber != nil { 98 t.Fatalf("CodeAt() was passed a block number when it should not have been") 99 } 100 101 bc.Call(&bind.CallOpts{BlockNumber: blockNumber, Pending: true}, nil, "something") 102 103 if !mc.pendingCallContractCalled { 104 t.Fatalf("CallContract() was not passed the block number") 105 } 106 107 if !mc.pendingCodeAtCalled { 108 t.Fatalf("CodeAt() was not passed the block number") 109 } 110 } 111 112 const hexData = "0x000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158" 113 114 func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { 115 hash := crypto.Keccak256Hash([]byte("testName")) 116 topics := []common.Hash{ 117 common.HexToHash("0x0"), 118 hash, 119 } 120 mockLog := newMockLog(topics, common.HexToHash("0x0")) 121 122 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"}]` 123 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 124 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 125 126 expectedReceivedMap := map[string]interface{}{ 127 "name": hash, 128 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 129 "amount": big.NewInt(1), 130 "memo": []byte{88}, 131 } 132 unpackAndCheck(t, bc, expectedReceivedMap, mockLog) 133 } 134 135 func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { 136 sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"}) 137 if err != nil { 138 t.Fatal(err) 139 } 140 hash := crypto.Keccak256Hash(sliceBytes) 141 topics := []common.Hash{ 142 common.HexToHash("0x0"), 143 hash, 144 } 145 mockLog := newMockLog(topics, common.HexToHash("0x0")) 146 147 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"}]` 148 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 149 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 150 151 expectedReceivedMap := map[string]interface{}{ 152 "names": hash, 153 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 154 "amount": big.NewInt(1), 155 "memo": []byte{88}, 156 } 157 unpackAndCheck(t, bc, expectedReceivedMap, mockLog) 158 } 159 160 func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) { 161 arrBytes, err := rlp.EncodeToBytes([2]common.Address{common.HexToAddress("0x0"), common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2")}) 162 if err != nil { 163 t.Fatal(err) 164 } 165 hash := crypto.Keccak256Hash(arrBytes) 166 topics := []common.Hash{ 167 common.HexToHash("0x0"), 168 hash, 169 } 170 mockLog := newMockLog(topics, common.HexToHash("0x0")) 171 172 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"}]` 173 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 174 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 175 176 expectedReceivedMap := map[string]interface{}{ 177 "addresses": hash, 178 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 179 "amount": big.NewInt(1), 180 "memo": []byte{88}, 181 } 182 unpackAndCheck(t, bc, expectedReceivedMap, mockLog) 183 } 184 185 func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) { 186 mockAddress := common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2") 187 addrBytes := mockAddress.Bytes() 188 hash := crypto.Keccak256Hash([]byte("mockFunction(address,uint)")) 189 functionSelector := hash[:4] 190 functionTyBytes := append(addrBytes, functionSelector...) 191 var functionTy [24]byte 192 copy(functionTy[:], functionTyBytes[0:24]) 193 topics := []common.Hash{ 194 common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"), 195 common.BytesToHash(functionTyBytes), 196 } 197 mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42")) 198 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"}]` 199 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 200 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 201 202 expectedReceivedMap := map[string]interface{}{ 203 "function": functionTy, 204 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 205 "amount": big.NewInt(1), 206 "memo": []byte{88}, 207 } 208 unpackAndCheck(t, bc, expectedReceivedMap, mockLog) 209 } 210 211 func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) { 212 bytes := []byte{1, 2, 3, 4, 5} 213 hash := crypto.Keccak256Hash(bytes) 214 topics := []common.Hash{ 215 common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"), 216 hash, 217 } 218 mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42")) 219 220 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"}]` 221 parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) 222 bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) 223 224 expectedReceivedMap := map[string]interface{}{ 225 "content": hash, 226 "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), 227 "amount": big.NewInt(1), 228 "memo": []byte{88}, 229 } 230 unpackAndCheck(t, bc, expectedReceivedMap, mockLog) 231 } 232 233 func unpackAndCheck(t *testing.T, bc *bind.BoundContract, expected map[string]interface{}, mockLog types.Log) { 234 received := make(map[string]interface{}) 235 if err := bc.UnpackLogIntoMap(received, "received", mockLog); err != nil { 236 t.Error(err) 237 } 238 239 if len(received) != len(expected) { 240 t.Fatalf("unpacked map length %v not equal expected length of %v", len(received), len(expected)) 241 } 242 for name, elem := range expected { 243 if !reflect.DeepEqual(elem, received[name]) { 244 t.Errorf("field %v does not match expected, want %v, got %v", name, elem, received[name]) 245 } 246 } 247 } 248 249 func newMockLog(topics []common.Hash, txHash common.Hash) types.Log { 250 return types.Log{ 251 Address: common.HexToAddress("0x0"), 252 Topics: topics, 253 Data: hexutil.MustDecode(hexData), 254 BlockNumber: uint64(26), 255 TxHash: txHash, 256 TxIndex: 111, 257 BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), 258 Index: 7, 259 Removed: false, 260 } 261 }