From 2b11e99225850bd9f51e50a1e26cf11dfc89b632 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Wed, 30 Sep 2020 13:20:40 +0300 Subject: [PATCH] core: fix CalculateNetworkFee for signature contracts First PUSHDATA1 is from invocation script, the second PUSHDATA1 is from verification script. E.g.: Invocation script: INDEX OPCODE PARAMETER 0 PUSHDATA1 035913b9588da23a5c3ce14b2886a6b8ebb6a0eb92bdaa948510dfb5ae5194d6cb << 35 PUSHNULL 36 SYSCALL Neo.Crypto.VerifyWithECDsaSecp256r1 (95440d78) Verification script: INDEX OPCODE PARAMETER 0 PUSHDATA1 3930fe5a9b44682f37741955df4a5f2585ed5aa438fa6e17ae51083673b1d64253e5a859c0cf168be67971e53a23c1c40582777d94a8e391db23ff613849627d << --- pkg/core/blockchain_test.go | 49 ++++++++++++++++++++++++++++++++----- pkg/core/util.go | 2 +- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 2347f03cc..78de1c9f9 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -215,7 +215,7 @@ func TestVerifyTx(t *testing.T) { bc := newTestChain(t) defer bc.Close() - accs := make([]*wallet.Account, 4) + accs := make([]*wallet.Account, 5) for i := range accs { var err error accs[i], err = wallet.NewAccount() @@ -291,11 +291,48 @@ func TestVerifyTx(t *testing.T) { require.NoError(t, accs[0].SignTx(tx)) checkErr(t, ErrTxTooBig, tx) }) - t.Run("SmallNetworkFee", func(t *testing.T) { - tx := bc.newTestTx(h, testScript) - tx.NetworkFee = 1 - require.NoError(t, accs[0].SignTx(tx)) - checkErr(t, ErrTxSmallNetworkFee, tx) + t.Run("NetworkFee", func(t *testing.T) { + t.Run("SmallNetworkFee", func(t *testing.T) { + tx := bc.newTestTx(h, testScript) + tx.NetworkFee = 1 + require.NoError(t, accs[0].SignTx(tx)) + checkErr(t, ErrTxSmallNetworkFee, tx) + }) + t.Run("CalculateNetworkFee, signature script", func(t *testing.T) { + tx := bc.newTestTx(h, testScript) + expectedSize := io.GetVarSize(tx) + verificationNetFee, calculatedScriptSize := CalculateNetworkFee(accs[0].Contract.Script) + expectedSize += calculatedScriptSize + expectedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte() + tx.NetworkFee = expectedNetFee + require.NoError(t, accs[0].SignTx(tx)) + actualSize := io.GetVarSize(tx) + require.Equal(t, expectedSize, actualSize) + interopCtx := bc.newInteropContext(trigger.Verification, bc.dao, nil, tx) + gasConsumed, err := bc.verifyHashAgainstScript(h, &tx.Scripts[0], interopCtx, -1) + require.NoError(t, err) + require.Equal(t, verificationNetFee, gasConsumed) + require.Equal(t, expectedNetFee, bc.FeePerByte()*int64(actualSize)+gasConsumed) + }) + t.Run("CalculateNetworkFee, multisignature script", func(t *testing.T) { + multisigAcc := accs[4] + pKeys := keys.PublicKeys{multisigAcc.PrivateKey().PublicKey()} + require.NoError(t, multisigAcc.ConvertMultisig(1, pKeys)) + multisigHash := hash.Hash160(multisigAcc.Contract.Script) + tx := bc.newTestTx(multisigHash, testScript) + verificationNetFee, calculatedScriptSize := CalculateNetworkFee(multisigAcc.Contract.Script) + expectedSize := io.GetVarSize(tx) + calculatedScriptSize + expectedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte() + tx.NetworkFee = expectedNetFee + require.NoError(t, multisigAcc.SignTx(tx)) + actualSize := io.GetVarSize(tx) + require.Equal(t, expectedSize, actualSize) + interopCtx := bc.newInteropContext(trigger.Verification, bc.dao, nil, tx) + gasConsumed, err := bc.verifyHashAgainstScript(multisigHash, &tx.Scripts[0], interopCtx, -1) + require.NoError(t, err) + require.Equal(t, verificationNetFee, gasConsumed) + require.Equal(t, expectedNetFee, bc.FeePerByte()*int64(actualSize)+gasConsumed) + }) }) t.Run("Conflict", func(t *testing.T) { balance := bc.GetUtilityTokenBalance(h).Int64() diff --git a/pkg/core/util.go b/pkg/core/util.go index 9ce81e47b..973c74c46 100644 --- a/pkg/core/util.go +++ b/pkg/core/util.go @@ -138,7 +138,7 @@ func CalculateNetworkFee(script []byte) (int64, int) { ) if vm.IsSignatureContract(script) { size += 67 + io.GetVarSize(script) - netFee += opcodePrice(opcode.PUSHDATA1, opcode.PUSHNULL) + crypto.ECDSAVerifyPrice + netFee += opcodePrice(opcode.PUSHDATA1, opcode.PUSHNULL, opcode.PUSHDATA1) + crypto.ECDSAVerifyPrice } else if m, pubs, ok := vm.ParseMultiSigContract(script); ok { n := len(pubs) sizeInv := 66 * m