github.com/klaytn/klaytn@v1.12.1/tests/validate_sender_test.go (about)

     1  // Copyright 2019 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn 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 klaytn 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 klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package tests
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"fmt"
    22  	"math/big"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/klaytn/klaytn/accounts/abi"
    28  	"github.com/klaytn/klaytn/blockchain/types"
    29  	"github.com/klaytn/klaytn/common"
    30  	"github.com/klaytn/klaytn/common/profile"
    31  	"github.com/klaytn/klaytn/crypto"
    32  	"github.com/klaytn/klaytn/log"
    33  	"github.com/klaytn/klaytn/params"
    34  	"github.com/stretchr/testify/assert"
    35  )
    36  
    37  // TestValidateSenderContract tests a precompiled contract "ValidateSender" whose address is 0xb.
    38  // This contract validates the signature that is signed by the sender with the msgHash.
    39  func TestValidateSenderContract(t *testing.T) {
    40  	log.EnableLogForTest(log.LvlCrit, log.LvlTrace)
    41  	prof := profile.NewProfiler()
    42  
    43  	if isCompilerAvailable() == false {
    44  		if testing.Verbose() {
    45  			fmt.Printf("TestFeePayerContract is skipped due to the lack of solc.")
    46  		}
    47  		return
    48  	}
    49  
    50  	// Initialize blockchain
    51  	start := time.Now()
    52  	bcdata, err := NewBCData(6, 4)
    53  	if err != nil {
    54  		t.Fatal(err)
    55  	}
    56  	prof.Profile("main_init_blockchain", time.Now().Sub(start))
    57  	defer bcdata.Shutdown()
    58  
    59  	// Initialize address-balance map for verification
    60  	start = time.Now()
    61  	accountMap := NewAccountMap()
    62  	if err := accountMap.Initialize(bcdata); err != nil {
    63  		t.Fatal(err)
    64  	}
    65  	prof.Profile("main_init_accountMap", time.Now().Sub(start))
    66  
    67  	// reservoir account
    68  	reservoir := &TestAccountType{
    69  		Addr:  *bcdata.addrs[0],
    70  		Keys:  []*ecdsa.PrivateKey{bcdata.privKeys[0]},
    71  		Nonce: uint64(0),
    72  	}
    73  
    74  	// multisigInitial has a initial key pair of multisig before the account key update
    75  	multisigInitial, err := createAnonymousAccount("aa113e82881499a7a361e8354a5b68f6c6885c7bcba09ea2b0891480396c322e")
    76  	assert.Equal(t, nil, err)
    77  
    78  	// multisig2Initial has a initial key pair of multisig2 before the account key update
    79  	multisig2Initial, err := createAnonymousAccount("cc113e82881499a7a361e8354a5b68f6c6885c7bcba09ea2b0891480396c322e")
    80  	assert.Equal(t, nil, err)
    81  
    82  	multisig, err := createMultisigAccount(uint(2),
    83  		[]uint{1, 1, 1},
    84  		[]string{
    85  			"bb113e82881499a7a361e8354a5b68f6c6885c7bcba09ea2b0891480396c322e",
    86  			"a5c9a50938a089618167c9d67dbebc0deaffc3c76ddc6b40c2777ae59438e989",
    87  			"c32c471b732e2f56103e2f8e8cfd52792ef548f05f326e546a7d1fbf9d0419ec",
    88  		},
    89  		multisigInitial.Addr)
    90  
    91  	multisig2, err := createMultisigAccount(uint(2),
    92  		[]uint{1, 1, 1},
    93  		[]string{
    94  			"bb113e82881499a7a361e8354a5b68f6c6885c7bcba09ea2b0891480396c322f",
    95  			"a5c9a50938a089618167c9d67dbebc0deaffc3c76ddc6b40c2777ae59438e98a",
    96  			"c32c471b732e2f56103e2f8e8cfd52792ef548f05f326e546a7d1fbf9d0419ed",
    97  		},
    98  		multisig2Initial.Addr)
    99  
   100  	signer := types.LatestSignerForChainID(bcdata.bc.Config().ChainID)
   101  	gasPrice := new(big.Int).SetUint64(bcdata.bc.Config().UnitPrice)
   102  
   103  	// Transfer (reservoir -> multisig) using a legacy transaction.
   104  	{
   105  		var txs types.Transactions
   106  
   107  		amount := new(big.Int).Mul(big.NewInt(3000), new(big.Int).SetUint64(params.KLAY))
   108  		tx := types.NewTransaction(reservoir.Nonce,
   109  			multisig.Addr, amount, gasLimit, gasPrice, []byte{})
   110  
   111  		err := tx.SignWithKeys(signer, reservoir.Keys)
   112  		assert.Equal(t, nil, err)
   113  		txs = append(txs, tx)
   114  
   115  		if err := bcdata.GenABlockWithTransactions(accountMap, txs, prof); err != nil {
   116  			t.Fatal(err)
   117  		}
   118  		reservoir.Nonce += 1
   119  	}
   120  
   121  	// Update multisig account's key to a multisig key
   122  	{
   123  		var txs types.Transactions
   124  
   125  		values := map[types.TxValueKeyType]interface{}{
   126  			types.TxValueKeyNonce:      multisig.Nonce,
   127  			types.TxValueKeyFrom:       multisig.Addr,
   128  			types.TxValueKeyGasLimit:   gasLimit,
   129  			types.TxValueKeyGasPrice:   gasPrice,
   130  			types.TxValueKeyAccountKey: multisig.AccKey,
   131  		}
   132  		tx, err := types.NewTransactionWithMap(types.TxTypeAccountUpdate, values)
   133  		assert.Equal(t, nil, err)
   134  
   135  		err = tx.SignWithKeys(signer, multisigInitial.Keys)
   136  		assert.Equal(t, nil, err)
   137  
   138  		txs = append(txs, tx)
   139  
   140  		if err := bcdata.GenABlockWithTransactions(accountMap, txs, prof); err != nil {
   141  			t.Fatal(err)
   142  		}
   143  		multisig.Nonce += 1
   144  	}
   145  
   146  	// Transfer (reservoir -> multisig2) using a legacy transaction.
   147  	{
   148  		var txs types.Transactions
   149  
   150  		amount := new(big.Int).Mul(big.NewInt(3000), new(big.Int).SetUint64(params.KLAY))
   151  		tx := types.NewTransaction(reservoir.Nonce,
   152  			multisig2.Addr, amount, gasLimit, gasPrice, []byte{})
   153  
   154  		err := tx.SignWithKeys(signer, reservoir.Keys)
   155  		assert.Equal(t, nil, err)
   156  		txs = append(txs, tx)
   157  
   158  		if err := bcdata.GenABlockWithTransactions(accountMap, txs, prof); err != nil {
   159  			t.Fatal(err)
   160  		}
   161  		reservoir.Nonce += 1
   162  	}
   163  
   164  	// Update multisig2 account's key to a multisig key
   165  	{
   166  		var txs types.Transactions
   167  
   168  		values := map[types.TxValueKeyType]interface{}{
   169  			types.TxValueKeyNonce:      multisig2.Nonce,
   170  			types.TxValueKeyFrom:       multisig2.Addr,
   171  			types.TxValueKeyGasLimit:   gasLimit,
   172  			types.TxValueKeyGasPrice:   gasPrice,
   173  			types.TxValueKeyAccountKey: multisig2.AccKey,
   174  		}
   175  		tx, err := types.NewTransactionWithMap(types.TxTypeAccountUpdate, values)
   176  		assert.Equal(t, nil, err)
   177  
   178  		err = tx.SignWithKeys(signer, multisig2Initial.Keys)
   179  		assert.Equal(t, nil, err)
   180  
   181  		txs = append(txs, tx)
   182  
   183  		if err := bcdata.GenABlockWithTransactions(accountMap, txs, prof); err != nil {
   184  			t.Fatal(err)
   185  		}
   186  		multisig.Nonce += 1
   187  	}
   188  
   189  	// Deploy the contract `ValidateSender`.
   190  	start = time.Now()
   191  	filepath := "../contracts/validatesender/validate_sender.sol"
   192  	contracts, err := deployContract(filepath, bcdata, accountMap, prof)
   193  	if err != nil {
   194  		t.Fatal(err)
   195  	}
   196  	prof.Profile("main_deployContract", time.Now().Sub(start))
   197  
   198  	c := contracts["../contracts/validatesender/validate_sender.sol:ValidateSenderContract"]
   199  	abii, err := abi.JSON(strings.NewReader(c.abi))
   200  	assert.Equal(t, nil, err)
   201  
   202  	n := accountMap.GetNonce(*bcdata.addrs[0])
   203  
   204  	// Check if the validation is successful with valid parameters of multisig.
   205  	{
   206  		msg := crypto.Keccak256Hash([]byte{0x1})
   207  		sigs := make([]byte, 65*2)
   208  		s1, err := crypto.Sign(msg[:], multisig.Keys[0])
   209  		assert.Equal(t, nil, err)
   210  		s2, err := crypto.Sign(msg[:], multisig.Keys[1])
   211  		assert.Equal(t, nil, err)
   212  
   213  		copy(sigs[0:65], s1[0:65])
   214  		copy(sigs[65:130], s2[0:65])
   215  
   216  		data, err := abii.Pack("ValidateSender", multisig.Addr, msg, sigs)
   217  		if err != nil {
   218  			t.Fatal(err)
   219  		}
   220  
   221  		tx, err := types.NewTransactionWithMap(types.TxTypeSmartContractExecution, map[types.TxValueKeyType]interface{}{
   222  			types.TxValueKeyNonce:    n,
   223  			types.TxValueKeyGasPrice: big.NewInt(0),
   224  			types.TxValueKeyGasLimit: uint64(5000000),
   225  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   226  			types.TxValueKeyAmount:   big.NewInt(0),
   227  			types.TxValueKeyTo:       c.address,
   228  			types.TxValueKeyData:     data,
   229  		})
   230  		assert.Equal(t, nil, err)
   231  
   232  		err = tx.Sign(signer, bcdata.privKeys[0])
   233  		assert.Equal(t, nil, err)
   234  
   235  		// 3. Call the given function `ValidateSender`.
   236  		ret, err := callContract(bcdata, tx)
   237  		assert.Equal(t, nil, err)
   238  
   239  		// 4. Check the returned value.
   240  		var validated bool
   241  		if err := abii.UnpackIntoInterface(&validated, "ValidateSender", ret); err != nil {
   242  			t.Fatal(err)
   243  		}
   244  		assert.Equal(t, true, validated)
   245  	}
   246  
   247  	// Check if the validation is successful with valid parameters of reservoir.
   248  	{
   249  		msg := crypto.Keccak256Hash([]byte{0x1})
   250  		sigs := make([]byte, 65)
   251  		s1, err := crypto.Sign(msg[:], reservoir.Keys[0])
   252  		assert.Equal(t, nil, err)
   253  
   254  		copy(sigs[0:65], s1[0:65])
   255  
   256  		data, err := abii.Pack("ValidateSender", reservoir.Addr, msg, sigs)
   257  		if err != nil {
   258  			t.Fatal(err)
   259  		}
   260  
   261  		tx, err := types.NewTransactionWithMap(types.TxTypeSmartContractExecution, map[types.TxValueKeyType]interface{}{
   262  			types.TxValueKeyNonce:    n,
   263  			types.TxValueKeyGasPrice: big.NewInt(0),
   264  			types.TxValueKeyGasLimit: uint64(5000000),
   265  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   266  			types.TxValueKeyAmount:   big.NewInt(0),
   267  			types.TxValueKeyTo:       c.address,
   268  			types.TxValueKeyData:     data,
   269  		})
   270  		assert.Equal(t, nil, err)
   271  
   272  		err = tx.Sign(signer, bcdata.privKeys[0])
   273  		assert.Equal(t, nil, err)
   274  
   275  		// 3. Call the given function `ValidateSender`.
   276  		ret, err := callContract(bcdata, tx)
   277  		assert.Equal(t, nil, err)
   278  
   279  		// 4. Check the returned value.
   280  		var validated bool
   281  		if err := abii.UnpackIntoInterface(&validated, "ValidateSender", ret); err != nil {
   282  			t.Fatal(err)
   283  		}
   284  		assert.Equal(t, true, validated)
   285  	}
   286  
   287  	// Check if the validation is failed with wrong signature.
   288  	{
   289  		msg := crypto.Keccak256Hash([]byte{0x1})
   290  		sigs := make([]byte, 65)
   291  		s1, err := crypto.Sign(msg[:], multisig.Keys[0])
   292  		assert.Equal(t, nil, err)
   293  
   294  		copy(sigs[0:65], s1[0:65])
   295  
   296  		data, err := abii.Pack("ValidateSender", multisig.Addr, msg, sigs)
   297  		if err != nil {
   298  			t.Fatal(err)
   299  		}
   300  
   301  		tx, err := types.NewTransactionWithMap(types.TxTypeSmartContractExecution, map[types.TxValueKeyType]interface{}{
   302  			types.TxValueKeyNonce:    n,
   303  			types.TxValueKeyGasPrice: big.NewInt(0),
   304  			types.TxValueKeyGasLimit: uint64(5000000),
   305  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   306  			types.TxValueKeyAmount:   big.NewInt(0),
   307  			types.TxValueKeyTo:       c.address,
   308  			types.TxValueKeyData:     data,
   309  		})
   310  		assert.Equal(t, nil, err)
   311  
   312  		err = tx.Sign(signer, bcdata.privKeys[0])
   313  		assert.Equal(t, nil, err)
   314  
   315  		// 3. Call the given function `ValidateSender`.
   316  		ret, err := callContract(bcdata, tx)
   317  		assert.Equal(t, nil, err)
   318  
   319  		// 4. Check the returned value.
   320  		var validated bool
   321  		if err := abii.UnpackIntoInterface(&validated, "ValidateSender", ret); err != nil {
   322  			t.Fatal(err)
   323  		}
   324  		assert.Equal(t, false, validated)
   325  	}
   326  
   327  	// Check if the validation is failed with signed by multisig but the address was set to mulsig2.
   328  	{
   329  		msg := crypto.Keccak256Hash([]byte{0x1})
   330  		sigs := make([]byte, 65*2)
   331  		s1, err := crypto.Sign(msg[:], multisig.Keys[0])
   332  		assert.Equal(t, nil, err)
   333  		s2, err := crypto.Sign(msg[:], multisig.Keys[1])
   334  		assert.Equal(t, nil, err)
   335  
   336  		copy(sigs[0:65], s1[0:65])
   337  		copy(sigs[65:130], s2[0:65])
   338  
   339  		data, err := abii.Pack("ValidateSender", multisig2.Addr, msg, sigs)
   340  		if err != nil {
   341  			t.Fatal(err)
   342  		}
   343  
   344  		tx, err := types.NewTransactionWithMap(types.TxTypeSmartContractExecution, map[types.TxValueKeyType]interface{}{
   345  			types.TxValueKeyNonce:    n,
   346  			types.TxValueKeyGasPrice: big.NewInt(0),
   347  			types.TxValueKeyGasLimit: uint64(5000000),
   348  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   349  			types.TxValueKeyAmount:   big.NewInt(0),
   350  			types.TxValueKeyTo:       c.address,
   351  			types.TxValueKeyData:     data,
   352  		})
   353  		assert.Equal(t, nil, err)
   354  
   355  		err = tx.Sign(signer, bcdata.privKeys[0])
   356  		assert.Equal(t, nil, err)
   357  
   358  		// 3. Call the given function `ValidateSender`.
   359  		ret, err := callContract(bcdata, tx)
   360  		assert.Equal(t, nil, err)
   361  
   362  		// 4. Check the returned value.
   363  		var validated bool
   364  		if err := abii.UnpackIntoInterface(&validated, "ValidateSender", ret); err != nil {
   365  			t.Fatal(err)
   366  		}
   367  		assert.Equal(t, false, validated)
   368  	}
   369  
   370  	// Check if the validation is failed with an unknown address.
   371  	{
   372  		msg := crypto.Keccak256Hash([]byte{0x1})
   373  		sigs := make([]byte, 65*2)
   374  		s1, err := crypto.Sign(msg[:], multisig.Keys[0])
   375  		assert.Equal(t, nil, err)
   376  		s2, err := crypto.Sign(msg[:], multisig.Keys[1])
   377  		assert.Equal(t, nil, err)
   378  
   379  		copy(sigs[0:65], s1[0:65])
   380  		copy(sigs[65:130], s2[0:65])
   381  
   382  		var addr common.Address
   383  		addr.SetBytesFromFront([]byte(getRandomPrivateKeyString(t)))
   384  
   385  		data, err := abii.Pack("ValidateSender", addr, msg, sigs)
   386  		if err != nil {
   387  			t.Fatal(err)
   388  		}
   389  
   390  		tx, err := types.NewTransactionWithMap(types.TxTypeSmartContractExecution, map[types.TxValueKeyType]interface{}{
   391  			types.TxValueKeyNonce:    n,
   392  			types.TxValueKeyGasPrice: big.NewInt(0),
   393  			types.TxValueKeyGasLimit: uint64(5000000),
   394  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   395  			types.TxValueKeyAmount:   big.NewInt(0),
   396  			types.TxValueKeyTo:       c.address,
   397  			types.TxValueKeyData:     data,
   398  		})
   399  		assert.Equal(t, nil, err)
   400  
   401  		err = tx.Sign(signer, bcdata.privKeys[0])
   402  		assert.Equal(t, nil, err)
   403  
   404  		// 3. Call the given function `ValidateSender`.
   405  		ret, err := callContract(bcdata, tx)
   406  		assert.Equal(t, nil, err)
   407  
   408  		// 4. Check the returned value.
   409  		var validated bool
   410  		if err := abii.UnpackIntoInterface(&validated, "ValidateSender", ret); err != nil {
   411  			t.Fatal(err)
   412  		}
   413  		assert.Equal(t, false, validated)
   414  	}
   415  }