diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index e8df34de1..5aa3277c9 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1554,7 +1554,7 @@ func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *block return fmt.Errorf("%w: %d vs %d", ErrTxInvalidWitnessNum, len(t.Signers), len(t.Scripts)) } interopCtx := bc.newInteropContext(trigger.Verification, bc.dao, block, t) - gasLimit := t.NetworkFee + gasLimit := t.NetworkFee - int64(t.Size())*bc.FeePerByte() for i := range t.Signers { gasConsumed, err := bc.verifyHashAgainstScript(t.Signers[i].Account, &t.Scripts[i], interopCtx, gasLimit) if err != nil { diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 2347f03cc..98bd8b04a 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,68 @@ 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("AlmostEnoughNetworkFee", func(t *testing.T) { + tx := bc.newTestTx(h, testScript) + verificationNetFee, calcultedScriptSize := CalculateNetworkFee(accs[0].Contract.Script) + expectedSize := io.GetVarSize(tx) + calcultedScriptSize + calculatedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte() + tx.NetworkFee = calculatedNetFee - 1 + require.NoError(t, accs[0].SignTx(tx)) + require.Equal(t, expectedSize, io.GetVarSize(tx)) + checkErr(t, ErrVerificationFailed, tx) + }) + t.Run("EnoughNetworkFee", func(t *testing.T) { + tx := bc.newTestTx(h, testScript) + verificationNetFee, calcultedScriptSize := CalculateNetworkFee(accs[0].Contract.Script) + expectedSize := io.GetVarSize(tx) + calcultedScriptSize + calculatedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte() + tx.NetworkFee = calculatedNetFee + require.NoError(t, accs[0].SignTx(tx)) + require.Equal(t, expectedSize, io.GetVarSize(tx)) + require.NoError(t, bc.VerifyTx(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/helper_test.go b/pkg/core/helper_test.go index 1293365e9..e918bde1f 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -206,7 +206,7 @@ func TestCreateBasicChain(t *testing.T) { bw := io.NewBufBinWriter() b.EncodeBinary(bw.BinWriter) require.NoError(t, bw.Err) - t.Logf("Block1 hex: %s", bw.Bytes()) + t.Logf("Block1 hex: %s", hex.EncodeToString(bw.Bytes())) t.Logf("txMoveNeo hash: %s", txMoveNeo.Hash().StringLE()) t.Logf("txMoveNeo hex: %s", hex.EncodeToString(txMoveNeo.Bytes())) t.Logf("txMoveGas hash: %s", txMoveGas.Hash().StringLE()) 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 diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index 8b66cc3c5..1f1b121a7 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -54,11 +54,11 @@ type rpcTestCase struct { check func(t *testing.T, e *executor, result interface{}) } -const testContractHash = "4546ec6fcdaa1c3ccdb048526b78624b457b60a4" -const deploymentTxHash = "17be1bbb0fdecae18cd4c6a2db19311f47bd540371e2ea479a46b349a66aa0b3" +const testContractHash = "b0fda4dd46b8e5d207e86e774a4a133c6db69ee7" +const deploymentTxHash = "59f7b22b90e26f883a56b916c1580e3ee4f13caded686353cd77577e6194c173" -const verifyContractHash = "47ef649f9a77cad161ddaa28b39c7e450e5429e7" -const verifyContractAVM = "560340570300412d510830db4121700c14aa8acf859d4fe402b34e673f2156821796a488ebdb30716813cedb2869db289740" +const verifyContractHash = "c1213693b22cb0454a436d6e0bd76b8c0a3bfdf7" +const verifyContractAVM = "570300412d51083021700c14aa8acf859d4fe402b34e673f2156821796a488ebdb30716813cedb2869db289740" var rpcTestCases = map[string][]rpcTestCase{ "getapplicationlog": { @@ -643,12 +643,12 @@ var rpcTestCases = map[string][]rpcTestCase{ "sendrawtransaction": { { name: "positive", - params: `["000a0000008096980000000000721b130000000000b004000001aa8acf859d4fe402b34e673f2156821796a488eb01005d0300e87648170000000c1478ba4c24009fe510e136c9995a2e05215e1be4dc0c14aa8acf859d4fe402b34e673f2156821796a488eb13c00c087472616e736665720c1425059ecb4878d3a875f91c51ceded330d4575fde41627d5b523801420c40b99503c74bb1861b0b45060501dd090224f6c404aca8c02ccba3243c9b9691c1ef9e6b824d731f8fab27c56ba75609d32d2d176e97f56d9e3780610c83ebd41a290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78"]`, + params: `["000b0000008096980000000000261c130000000000b004000001aa8acf859d4fe402b34e673f2156821796a488eb01005d0300e87648170000000c1478ba4c24009fe510e136c9995a2e05215e1be4dc0c14aa8acf859d4fe402b34e673f2156821796a488eb13c00c087472616e736665720c1425059ecb4878d3a875f91c51ceded330d4575fde41627d5b523801420c40ea2f56acf7f64629dc922d65a60176f3963afd4b7c259f2017a3a5139346f8ea54704624590832acb7794069ab2983ddc862b03b6a33d4428cd4c45cbc0941c2290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78"]`, result: func(e *executor) interface{} { return &result.RelayResult{} }, check: func(t *testing.T, e *executor, inv interface{}) { res, ok := inv.(*result.RelayResult) require.True(t, ok) - expectedHash, err := util.Uint256DecodeStringLE("8b6e610a2205914411b26c4380594fa9a1e16961ff5896ed3b16831a151c6dd0") + expectedHash, err := util.Uint256DecodeStringLE("ab5573cfc8d70774f04aa7d5521350cfc1aa1239c44c24e490e139408cd46a57") require.NoError(t, err) assert.Equal(t, expectedHash, res.Hash) }, @@ -1075,7 +1075,7 @@ func checkNep5Balances(t *testing.T, e *executor, acc interface{}) { }, { Asset: e.chain.UtilityTokenHash(), - Amount: "799.59495030", + Amount: "799.59641770", LastUpdated: 7, }}, Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(), diff --git a/pkg/rpc/server/testdata/testblocks.acc b/pkg/rpc/server/testdata/testblocks.acc index decc2c137..722d3c9a8 100644 Binary files a/pkg/rpc/server/testdata/testblocks.acc and b/pkg/rpc/server/testdata/testblocks.acc differ