github.com/klaytn/klaytn@v1.12.1/tests/precompiled_contracts_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/sha256"
    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/hexutil"
    31  	"github.com/klaytn/klaytn/common/profile"
    32  	"github.com/klaytn/klaytn/crypto"
    33  	"github.com/stretchr/testify/require"
    34  	"golang.org/x/crypto/ripemd160"
    35  )
    36  
    37  func TestPrecompiledContract(t *testing.T) {
    38  	prof := profile.NewProfiler()
    39  
    40  	if isCompilerAvailable() == false {
    41  		if testing.Verbose() {
    42  			fmt.Printf("TestFeePayerContract is skipped due to the lack of solc.")
    43  		}
    44  		return
    45  	}
    46  
    47  	// Initialize blockchain
    48  	start := time.Now()
    49  	bcdata, err := NewBCData(2000, 4)
    50  	if err != nil {
    51  		t.Fatal(err)
    52  	}
    53  	prof.Profile("main_init_blockchain", time.Now().Sub(start))
    54  	defer bcdata.Shutdown()
    55  
    56  	// Initialize address-balance map for verification
    57  	start = time.Now()
    58  	accountMap := NewAccountMap()
    59  	if err := accountMap.Initialize(bcdata); err != nil {
    60  		t.Fatal(err)
    61  	}
    62  	prof.Profile("main_init_accountMap", time.Now().Sub(start))
    63  
    64  	// Deploy the contract.
    65  	start = time.Now()
    66  	filepath := "../contracts/precompiledContracts/precompiled.sol"
    67  	contracts, err := deployContract(filepath, bcdata, accountMap, prof)
    68  	if err != nil {
    69  		t.Fatal(err)
    70  	}
    71  	prof.Profile("main_deployContract", time.Now().Sub(start))
    72  
    73  	signer := types.MakeSigner(bcdata.bc.Config(), bcdata.bc.CurrentHeader().Number)
    74  
    75  	// PrecompiledContracts 0x01: ecrecover
    76  	{
    77  		c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledEcrecover"]
    78  		abii, err := abi.JSON(strings.NewReader(c.abi))
    79  
    80  		hash := crypto.Keccak256Hash([]byte{1, 2, 3, 4})
    81  		sig, err := crypto.Sign(hash[:], bcdata.privKeys[0])
    82  		require.NoError(t, err)
    83  
    84  		v := sig[crypto.RecoveryIDOffset] + 27
    85  		var r, s [32]byte
    86  		copy(r[:], sig[:32])
    87  		copy(s[:], sig[32:64])
    88  
    89  		// Make an input data for the contract call.
    90  		data, err := abii.Pack("callEcrecover", hash, v, r, s)
    91  		if err != nil {
    92  			t.Fatal(err)
    93  		}
    94  
    95  		n := accountMap.GetNonce(*bcdata.addrs[0])
    96  
    97  		tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{
    98  			types.TxValueKeyNonce:    n,
    99  			types.TxValueKeyFeePayer: *bcdata.addrs[1],
   100  			types.TxValueKeyGasPrice: big.NewInt(0),
   101  			types.TxValueKeyGasLimit: uint64(5000000),
   102  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   103  			types.TxValueKeyAmount:   big.NewInt(0),
   104  			types.TxValueKeyTo:       c.address,
   105  			types.TxValueKeyData:     data,
   106  		})
   107  		require.Equal(t, nil, err)
   108  
   109  		err = tx.Sign(signer, bcdata.privKeys[0])
   110  		require.Equal(t, nil, err)
   111  
   112  		err = tx.SignFeePayer(signer, bcdata.privKeys[1])
   113  		require.Equal(t, nil, err)
   114  
   115  		ret, err := callContract(bcdata, tx)
   116  		require.Equal(t, nil, err)
   117  
   118  		// Check the returned value.
   119  		var addr common.Address
   120  		if err := abii.UnpackIntoInterface(&addr, "callEcrecover", ret); err != nil {
   121  			t.Fatal(err)
   122  		}
   123  		require.Equal(t, *bcdata.addrs[0], addr)
   124  	}
   125  
   126  	// PrecompiledContracts 0x02: sha256
   127  	{
   128  		c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledSha256Hash"]
   129  		abii, err := abi.JSON(strings.NewReader(c.abi))
   130  
   131  		fn := "callSha256"
   132  
   133  		dd := []byte{1, 2, 3, 4}
   134  		hash := sha256.Sum256(dd)
   135  
   136  		// Make an input data for the contract call.
   137  		data, err := abii.Pack(fn, dd)
   138  		if err != nil {
   139  			t.Fatal(err)
   140  		}
   141  
   142  		n := accountMap.GetNonce(*bcdata.addrs[0])
   143  
   144  		tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{
   145  			types.TxValueKeyNonce:    n,
   146  			types.TxValueKeyFeePayer: *bcdata.addrs[1],
   147  			types.TxValueKeyGasPrice: big.NewInt(0),
   148  			types.TxValueKeyGasLimit: uint64(5000000),
   149  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   150  			types.TxValueKeyAmount:   big.NewInt(0),
   151  			types.TxValueKeyTo:       c.address,
   152  			types.TxValueKeyData:     data,
   153  		})
   154  		require.Equal(t, nil, err)
   155  
   156  		err = tx.Sign(signer, bcdata.privKeys[0])
   157  		require.Equal(t, nil, err)
   158  
   159  		err = tx.SignFeePayer(signer, bcdata.privKeys[1])
   160  		require.Equal(t, nil, err)
   161  
   162  		ret, err := callContract(bcdata, tx)
   163  		require.Equal(t, nil, err)
   164  
   165  		// Check the returned value.
   166  		var addr [32]byte
   167  		var bb [32]byte
   168  		copy(bb[:], hash[:])
   169  		if err := abii.UnpackIntoInterface(&addr, fn, ret); err != nil {
   170  			t.Fatal(err)
   171  		}
   172  		require.Equal(t, bb, addr)
   173  	}
   174  
   175  	// PrecompiledContracts 0x03: ripemd160
   176  	{
   177  		c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledRipemd160Hash"]
   178  		abii, err := abi.JSON(strings.NewReader(c.abi))
   179  
   180  		fn := "callRipemd160"
   181  
   182  		dd := []byte{1, 2, 3, 4}
   183  		ripemd := ripemd160.New()
   184  		ripemd.Write(dd)
   185  		hash := ripemd.Sum(nil)
   186  
   187  		// Make an input data for the contract call.
   188  		data, err := abii.Pack(fn, dd)
   189  		if err != nil {
   190  			t.Fatal(err)
   191  		}
   192  
   193  		n := accountMap.GetNonce(*bcdata.addrs[0])
   194  
   195  		tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{
   196  			types.TxValueKeyNonce:    n,
   197  			types.TxValueKeyFeePayer: *bcdata.addrs[1],
   198  			types.TxValueKeyGasPrice: big.NewInt(0),
   199  			types.TxValueKeyGasLimit: uint64(5000000),
   200  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   201  			types.TxValueKeyAmount:   big.NewInt(0),
   202  			types.TxValueKeyTo:       c.address,
   203  			types.TxValueKeyData:     data,
   204  		})
   205  		require.Equal(t, nil, err)
   206  
   207  		err = tx.Sign(signer, bcdata.privKeys[0])
   208  		require.Equal(t, nil, err)
   209  
   210  		err = tx.SignFeePayer(signer, bcdata.privKeys[1])
   211  		require.Equal(t, nil, err)
   212  
   213  		ret, err := callContract(bcdata, tx)
   214  		require.Equal(t, nil, err)
   215  
   216  		// Check the returned value.
   217  		var addr [32]byte
   218  		var bb [32]byte
   219  		copy(bb[:], hash[:])
   220  		if err := abii.UnpackIntoInterface(&addr, fn, ret); err != nil {
   221  			t.Fatal(err)
   222  		}
   223  		require.Equal(t, bb, addr)
   224  	}
   225  
   226  	// PrecompiledContracts 0x04: datacopy (identity)
   227  	{
   228  		c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledDatacopy"]
   229  		abii, err := abi.JSON(strings.NewReader(c.abi))
   230  
   231  		fn := "callDatacopy"
   232  
   233  		dd := []byte{1, 2, 3, 4}
   234  
   235  		// Make an input data for the contract call.
   236  		data, err := abii.Pack(fn, dd)
   237  		if err != nil {
   238  			t.Fatal(err)
   239  		}
   240  
   241  		n := accountMap.GetNonce(*bcdata.addrs[0])
   242  
   243  		tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{
   244  			types.TxValueKeyNonce:    n,
   245  			types.TxValueKeyFeePayer: *bcdata.addrs[1],
   246  			types.TxValueKeyGasPrice: big.NewInt(0),
   247  			types.TxValueKeyGasLimit: uint64(5000000),
   248  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   249  			types.TxValueKeyAmount:   big.NewInt(0),
   250  			types.TxValueKeyTo:       c.address,
   251  			types.TxValueKeyData:     data,
   252  		})
   253  		require.Equal(t, nil, err)
   254  
   255  		err = tx.Sign(signer, bcdata.privKeys[0])
   256  		require.Equal(t, nil, err)
   257  
   258  		err = tx.SignFeePayer(signer, bcdata.privKeys[1])
   259  		require.Equal(t, nil, err)
   260  
   261  		ret, err := callContract(bcdata, tx)
   262  		require.Equal(t, nil, err)
   263  
   264  		// Check the returned value.
   265  		var addr []byte
   266  		if err := abii.UnpackIntoInterface(&addr, fn, ret); err != nil {
   267  			t.Fatal(err)
   268  		}
   269  		require.Equal(t, dd, addr)
   270  	}
   271  
   272  	// PrecompiledContracts 0x05: bigModExp
   273  	{
   274  		c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledBigModExp"]
   275  		abii, err := abi.JSON(strings.NewReader(c.abi))
   276  
   277  		fn := "callBigModExp"
   278  
   279  		var base, exp, mod [32]byte
   280  		copy(base[:], hexutil.MustDecode("0x0000000000000000000000000000000462e4ded88953a39ce849a8a7fa163fa9"))
   281  		copy(exp[:], hexutil.MustDecode("0x1f4a3123ff1223a1b0d040057af8a9fe70baa9258e0b959273ffc5718c6d4cc7"))
   282  		copy(mod[:], hexutil.MustDecode("0x00000000000000000000000000077d29a9c710b7e616683f194f18c43b43b869"))
   283  
   284  		// Make an input data for the contract call.
   285  		data, err := abii.Pack(fn, base, exp, mod)
   286  		if err != nil {
   287  			t.Fatal(err)
   288  		}
   289  
   290  		n := accountMap.GetNonce(*bcdata.addrs[0])
   291  
   292  		tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{
   293  			types.TxValueKeyNonce:    n,
   294  			types.TxValueKeyFeePayer: *bcdata.addrs[1],
   295  			types.TxValueKeyGasPrice: big.NewInt(0),
   296  			types.TxValueKeyGasLimit: uint64(5000000),
   297  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   298  			types.TxValueKeyAmount:   big.NewInt(0),
   299  			types.TxValueKeyTo:       c.address,
   300  			types.TxValueKeyData:     data,
   301  		})
   302  		require.Equal(t, nil, err)
   303  
   304  		err = tx.Sign(signer, bcdata.privKeys[0])
   305  		require.Equal(t, nil, err)
   306  
   307  		err = tx.SignFeePayer(signer, bcdata.privKeys[1])
   308  		require.Equal(t, nil, err)
   309  
   310  		ret, err := callContract(bcdata, tx)
   311  		require.Equal(t, nil, err)
   312  
   313  		// Check the returned value.
   314  		var result [32]byte
   315  		if err := abii.UnpackIntoInterface(&result, fn, ret); err != nil {
   316  			t.Fatal(err)
   317  		}
   318  		require.Equal(t, hexutil.MustDecode("0x0000000000000000000000000002dc17ba6bb47224fccc9a5ece97e2f691b4aa"), result[:])
   319  	}
   320  
   321  	// PrecompiledContracts 0x06: bn256Add
   322  	{
   323  		c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledBn256Add"]
   324  		abii, err := abi.JSON(strings.NewReader(c.abi))
   325  
   326  		fn := "callBn256Add"
   327  
   328  		var ax, ay, bx, by [32]byte
   329  		copy(ax[:], hexutil.MustDecode("0x17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa9"))
   330  		copy(ay[:], hexutil.MustDecode("0x01e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c"))
   331  		copy(bx[:], hexutil.MustDecode("0x039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869"))
   332  		copy(by[:], hexutil.MustDecode("0x073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98"))
   333  
   334  		// Make an input data for the contract call.
   335  		data, err := abii.Pack(fn, ax, ay, bx, by)
   336  		if err != nil {
   337  			t.Fatal(err)
   338  		}
   339  
   340  		n := accountMap.GetNonce(*bcdata.addrs[0])
   341  
   342  		tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{
   343  			types.TxValueKeyNonce:    n,
   344  			types.TxValueKeyFeePayer: *bcdata.addrs[1],
   345  			types.TxValueKeyGasPrice: big.NewInt(0),
   346  			types.TxValueKeyGasLimit: uint64(5000000),
   347  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   348  			types.TxValueKeyAmount:   big.NewInt(0),
   349  			types.TxValueKeyTo:       c.address,
   350  			types.TxValueKeyData:     data,
   351  		})
   352  		require.Equal(t, nil, err)
   353  
   354  		err = tx.Sign(signer, bcdata.privKeys[0])
   355  		require.Equal(t, nil, err)
   356  
   357  		err = tx.SignFeePayer(signer, bcdata.privKeys[1])
   358  		require.Equal(t, nil, err)
   359  
   360  		ret, err := callContract(bcdata, tx)
   361  		require.Equal(t, nil, err)
   362  
   363  		// Check the returned value.
   364  		var result [2][32]byte
   365  		if err := abii.UnpackIntoInterface(&result, fn, ret); err != nil {
   366  			t.Fatal(err)
   367  		}
   368  		require.Equal(t, hexutil.MustDecode("0x15bf2bb17880144b5d1cd2b1f46eff9d617bffd1ca57c37fb5a49bd84e53cf66"), result[0][:])
   369  		require.Equal(t, hexutil.MustDecode("0x049c797f9ce0d17083deb32b5e36f2ea2a212ee036598dd7624c168993d1355f"), result[1][:])
   370  	}
   371  
   372  	// PrecompiledContracts 0x07: bn256ScalarMul
   373  	{
   374  		c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledBn256ScalarMul"]
   375  		abii, err := abi.JSON(strings.NewReader(c.abi))
   376  
   377  		fn := "callBn256ScalarMul"
   378  
   379  		var ax, ay, scalar [32]byte
   380  		copy(ax[:], hexutil.MustDecode("0x2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb7"))
   381  		copy(ay[:], hexutil.MustDecode("0x21611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb204"))
   382  		copy(scalar[:], hexutil.MustDecode("0x00000000000000000000000000000000000000000000000011138ce750fa15c2"))
   383  
   384  		// Make an input data for the contract call.
   385  		data, err := abii.Pack(fn, ax, ay, scalar)
   386  		if err != nil {
   387  			t.Fatal(err)
   388  		}
   389  
   390  		n := accountMap.GetNonce(*bcdata.addrs[0])
   391  
   392  		tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{
   393  			types.TxValueKeyNonce:    n,
   394  			types.TxValueKeyFeePayer: *bcdata.addrs[1],
   395  			types.TxValueKeyGasPrice: big.NewInt(0),
   396  			types.TxValueKeyGasLimit: uint64(5000000),
   397  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   398  			types.TxValueKeyAmount:   big.NewInt(0),
   399  			types.TxValueKeyTo:       c.address,
   400  			types.TxValueKeyData:     data,
   401  		})
   402  		require.Equal(t, nil, err)
   403  
   404  		err = tx.Sign(signer, bcdata.privKeys[0])
   405  		require.Equal(t, nil, err)
   406  
   407  		err = tx.SignFeePayer(signer, bcdata.privKeys[1])
   408  		require.Equal(t, nil, err)
   409  
   410  		ret, err := callContract(bcdata, tx)
   411  		require.Equal(t, nil, err)
   412  
   413  		// Check the returned value.
   414  		var result [2][32]byte
   415  		if err := abii.UnpackIntoInterface(&result, fn, ret); err != nil {
   416  			t.Fatal(err)
   417  		}
   418  		require.Equal(t, hexutil.MustDecode("0x070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c"), result[0][:])
   419  		require.Equal(t, hexutil.MustDecode("0x031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc"), result[1][:])
   420  	}
   421  
   422  	// PrecompiledContracts 0x08: bn256Paring
   423  	{
   424  		c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledBn256Pairing"]
   425  		abii, err := abi.JSON(strings.NewReader(c.abi))
   426  
   427  		fn := "callBn256Pairing"
   428  
   429  		x1 := hexutil.MustDecode("0x1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59")
   430  		y1 := hexutil.MustDecode("0x3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41")
   431  		x2 := hexutil.MustDecode("0x209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7")
   432  		y2 := hexutil.MustDecode("0x04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678")
   433  		x3 := hexutil.MustDecode("0x2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d")
   434  		y3 := hexutil.MustDecode("0x120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550")
   435  		x4 := hexutil.MustDecode("0x111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c")
   436  		y4 := hexutil.MustDecode("0x2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411")
   437  		x5 := hexutil.MustDecode("0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2")
   438  		y5 := hexutil.MustDecode("0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed")
   439  		x6 := hexutil.MustDecode("0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b")
   440  		y6 := hexutil.MustDecode("0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa")
   441  
   442  		input := make([]byte, 32*2*6)
   443  		copy(input[32*0:32*1], x1)
   444  		copy(input[32*1:32*2], y1)
   445  		copy(input[32*2:32*3], x2)
   446  		copy(input[32*3:32*4], y2)
   447  		copy(input[32*4:32*5], x3)
   448  		copy(input[32*5:32*6], y3)
   449  		copy(input[32*6:32*7], x4)
   450  		copy(input[32*7:32*8], y4)
   451  		copy(input[32*8:32*9], x5)
   452  		copy(input[32*9:32*10], y5)
   453  		copy(input[32*10:32*11], x6)
   454  		copy(input[32*11:32*12], y6)
   455  
   456  		// Make an input data for the contract call.
   457  		data, err := abii.Pack(fn, input)
   458  		if err != nil {
   459  			t.Fatal(err)
   460  		}
   461  
   462  		n := accountMap.GetNonce(*bcdata.addrs[0])
   463  
   464  		tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{
   465  			types.TxValueKeyNonce:    n,
   466  			types.TxValueKeyFeePayer: *bcdata.addrs[1],
   467  			types.TxValueKeyGasPrice: big.NewInt(0),
   468  			types.TxValueKeyGasLimit: uint64(5000000),
   469  			types.TxValueKeyFrom:     *bcdata.addrs[0],
   470  			types.TxValueKeyAmount:   big.NewInt(0),
   471  			types.TxValueKeyTo:       c.address,
   472  			types.TxValueKeyData:     data,
   473  		})
   474  		require.Equal(t, nil, err)
   475  
   476  		err = tx.Sign(signer, bcdata.privKeys[0])
   477  		require.Equal(t, nil, err)
   478  
   479  		err = tx.SignFeePayer(signer, bcdata.privKeys[1])
   480  		require.Equal(t, nil, err)
   481  
   482  		ret, err := callContract(bcdata, tx)
   483  		require.Equal(t, nil, err)
   484  
   485  		// Check the returned value.
   486  		var result [32]byte
   487  		if err := abii.UnpackIntoInterface(&result, fn, ret); err != nil {
   488  			t.Fatal(err)
   489  		}
   490  		require.Equal(t, hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000001"), result[:])
   491  	}
   492  }