github.com/core-coin/go-core/v2@v2.1.9/accounts/abi/bind/base_test.go (about)

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