core: move CalculateNetworkFee to a separate package

This commit is contained in:
Evgenii Stratonikov 2020-09-28 17:56:16 +03:00
parent d6a1a22afa
commit 9733a6f394
10 changed files with 66 additions and 55 deletions

View file

@ -9,6 +9,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/native"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
@ -344,7 +345,7 @@ func signTx(t *testing.T, feePerByte int64, txs ...*transaction.Transaction) {
require.NoError(t, err) require.NoError(t, err)
for _, tx := range txs { for _, tx := range txs {
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := core.CalculateNetworkFee(rawScript) netFee, sizeDelta := fee.Calculate(rawScript)
tx.NetworkFee += +netFee tx.NetworkFee += +netFee
size += sizeDelta size += sizeDelta
tx.NetworkFee += int64(size) * feePerByte tx.NetworkFee += int64(size) * feePerByte

View file

@ -9,6 +9,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/core/mempool" "github.com/nspcc-dev/neo-go/pkg/core/mempool"
"github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/native"
@ -300,7 +301,7 @@ func TestVerifyTx(t *testing.T) {
}) })
t.Run("AlmostEnoughNetworkFee", func(t *testing.T) { t.Run("AlmostEnoughNetworkFee", func(t *testing.T) {
tx := bc.newTestTx(h, testScript) tx := bc.newTestTx(h, testScript)
verificationNetFee, calcultedScriptSize := CalculateNetworkFee(accs[0].Contract.Script) verificationNetFee, calcultedScriptSize := fee.Calculate(accs[0].Contract.Script)
expectedSize := io.GetVarSize(tx) + calcultedScriptSize expectedSize := io.GetVarSize(tx) + calcultedScriptSize
calculatedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte() calculatedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte()
tx.NetworkFee = calculatedNetFee - 1 tx.NetworkFee = calculatedNetFee - 1
@ -310,7 +311,7 @@ func TestVerifyTx(t *testing.T) {
}) })
t.Run("EnoughNetworkFee", func(t *testing.T) { t.Run("EnoughNetworkFee", func(t *testing.T) {
tx := bc.newTestTx(h, testScript) tx := bc.newTestTx(h, testScript)
verificationNetFee, calcultedScriptSize := CalculateNetworkFee(accs[0].Contract.Script) verificationNetFee, calcultedScriptSize := fee.Calculate(accs[0].Contract.Script)
expectedSize := io.GetVarSize(tx) + calcultedScriptSize expectedSize := io.GetVarSize(tx) + calcultedScriptSize
calculatedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte() calculatedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte()
tx.NetworkFee = calculatedNetFee tx.NetworkFee = calculatedNetFee
@ -321,7 +322,7 @@ func TestVerifyTx(t *testing.T) {
t.Run("CalculateNetworkFee, signature script", func(t *testing.T) { t.Run("CalculateNetworkFee, signature script", func(t *testing.T) {
tx := bc.newTestTx(h, testScript) tx := bc.newTestTx(h, testScript)
expectedSize := io.GetVarSize(tx) expectedSize := io.GetVarSize(tx)
verificationNetFee, calculatedScriptSize := CalculateNetworkFee(accs[0].Contract.Script) verificationNetFee, calculatedScriptSize := fee.Calculate(accs[0].Contract.Script)
expectedSize += calculatedScriptSize expectedSize += calculatedScriptSize
expectedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte() expectedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte()
tx.NetworkFee = expectedNetFee tx.NetworkFee = expectedNetFee
@ -340,7 +341,7 @@ func TestVerifyTx(t *testing.T) {
require.NoError(t, multisigAcc.ConvertMultisig(1, pKeys)) require.NoError(t, multisigAcc.ConvertMultisig(1, pKeys))
multisigHash := hash.Hash160(multisigAcc.Contract.Script) multisigHash := hash.Hash160(multisigAcc.Contract.Script)
tx := bc.newTestTx(multisigHash, testScript) tx := bc.newTestTx(multisigHash, testScript)
verificationNetFee, calculatedScriptSize := CalculateNetworkFee(multisigAcc.Contract.Script) verificationNetFee, calculatedScriptSize := fee.Calculate(multisigAcc.Contract.Script)
expectedSize := io.GetVarSize(tx) + calculatedScriptSize expectedSize := io.GetVarSize(tx) + calculatedScriptSize
expectedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte() expectedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte()
tx.NetworkFee = expectedNetFee tx.NetworkFee = expectedNetFee
@ -440,7 +441,7 @@ func TestVerifyTx(t *testing.T) {
rawScript := testchain.CommitteeVerificationScript() rawScript := testchain.CommitteeVerificationScript()
require.NoError(t, err) require.NoError(t, err)
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := CalculateNetworkFee(rawScript) netFee, sizeDelta := fee.Calculate(rawScript)
tx.NetworkFee += netFee tx.NetworkFee += netFee
tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte() tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte()
data := tx.GetSignedPart() data := tx.GetSignedPart()
@ -479,7 +480,7 @@ func TestVerifyTx(t *testing.T) {
Scopes: transaction.None, Scopes: transaction.None,
}} }}
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := CalculateNetworkFee(oracleScript) netFee, sizeDelta := fee.Calculate(oracleScript)
tx.NetworkFee += netFee tx.NetworkFee += netFee
tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte() tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte()
return tx return tx

39
pkg/core/fee/calculate.go Normal file
View file

@ -0,0 +1,39 @@
package fee
import (
"github.com/nspcc-dev/neo-go/pkg/core/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
)
// Calculate returns network fee for transaction
func Calculate(script []byte) (int64, int) {
var (
netFee int64
size int
)
if vm.IsSignatureContract(script) {
size += 67 + io.GetVarSize(script)
netFee += Opcode(opcode.PUSHDATA1, opcode.PUSHNULL, opcode.PUSHDATA1) + crypto.ECDSAVerifyPrice
} else if m, pubs, ok := vm.ParseMultiSigContract(script); ok {
n := len(pubs)
sizeInv := 66 * m
size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script)
netFee += calculateMultisig(m) + calculateMultisig(n)
netFee += Opcode(opcode.PUSHNULL) + crypto.ECDSAVerifyPrice*int64(n)
} else {
// We can support more contract types in the future.
}
return netFee, size
}
func calculateMultisig(n int) int64 {
result := Opcode(opcode.PUSHDATA1) * int64(n)
bw := io.NewBufBinWriter()
emit.Int(bw.BinWriter, int64(n))
// it's a hack because prices of small PUSH* opcodes are equal
result += Opcode(opcode.Opcode(bw.Bytes()[0]))
return result
}

View file

@ -1,11 +1,9 @@
package core package fee
import ( import "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
)
// opcodePrice returns the deployment prices of specified opcodes // Opcode returns the deployment prices of specified opcodes.
func opcodePrice(opcodes ...opcode.Opcode) int64 { func Opcode(opcodes ...opcode.Opcode) int64 {
var result int64 var result int64
for _, op := range opcodes { for _, op := range opcodes {
result += prices[op] result += prices[op]

View file

@ -1,6 +1,7 @@
package core package core
import ( import (
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
) )
@ -10,5 +11,5 @@ const StoragePrice = 100000
// getPrice returns a price for executing op with the provided parameter. // getPrice returns a price for executing op with the provided parameter.
func getPrice(v *vm.VM, op opcode.Opcode, parameter []byte) int64 { func getPrice(v *vm.VM, op opcode.Opcode, parameter []byte) int64 {
return opcodePrice(op) return fee.Opcode(op)
} }

View file

@ -14,6 +14,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/compiler" "github.com/nspcc-dev/neo-go/pkg/compiler"
"github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/native"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
@ -407,7 +408,7 @@ func signTx(bc *Blockchain, txs ...*transaction.Transaction) error {
} }
for _, tx := range txs { for _, tx := range txs {
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := CalculateNetworkFee(rawScript) netFee, sizeDelta := fee.Calculate(rawScript)
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
tx.NetworkFee += int64(size) * bc.FeePerByte() tx.NetworkFee += int64(size) * bc.FeePerByte()
@ -422,13 +423,13 @@ func signTx(bc *Blockchain, txs ...*transaction.Transaction) error {
func addNetworkFee(bc *Blockchain, tx *transaction.Transaction, sender *wallet.Account) error { func addNetworkFee(bc *Blockchain, tx *transaction.Transaction, sender *wallet.Account) error {
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := CalculateNetworkFee(sender.Contract.Script) netFee, sizeDelta := fee.Calculate(sender.Contract.Script)
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
for _, cosigner := range tx.Signers { for _, cosigner := range tx.Signers {
contract := bc.GetContractState(cosigner.Account) contract := bc.GetContractState(cosigner.Account)
if contract != nil { if contract != nil {
netFee, sizeDelta = CalculateNetworkFee(contract.Script) netFee, sizeDelta = fee.Calculate(contract.Script)
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
} }

View file

@ -7,7 +7,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
@ -15,7 +14,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
) )
@ -129,33 +127,3 @@ func headerSliceReverse(dest []*block.Header) {
dest[i], dest[j] = dest[j], dest[i] dest[i], dest[j] = dest[j], dest[i]
} }
} }
// CalculateNetworkFee returns network fee for transaction
func CalculateNetworkFee(script []byte) (int64, int) {
var (
netFee int64
size int
)
if vm.IsSignatureContract(script) {
size += 67 + io.GetVarSize(script)
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
size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script)
netFee += calculateMultisigFee(m) + calculateMultisigFee(n)
netFee += opcodePrice(opcode.PUSHNULL) + crypto.ECDSAVerifyPrice*int64(n)
} else {
// We can support more contract types in the future.
}
return netFee, size
}
func calculateMultisigFee(n int) int64 {
result := opcodePrice(opcode.PUSHDATA1) * int64(n)
bw := io.NewBufBinWriter()
emit.Int(bw.BinWriter, int64(n))
// it's a hack because prices of small PUSH* opcodes are equal
result += opcodePrice(opcode.Opcode(bw.Bytes()[0]))
return result
}

View file

@ -7,6 +7,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@ -552,7 +553,7 @@ func (c *Client) AddNetworkFee(tx *transaction.Transaction, extraFee int64, accs
size += io.GetVarSize([]byte{}) * 2 // both scripts are empty size += io.GetVarSize([]byte{}) * 2 // both scripts are empty
continue continue
} }
netFee, sizeDelta := core.CalculateNetworkFee(accs[i].Contract.Script) netFee, sizeDelta := fee.Calculate(accs[i].Contract.Script)
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
} }

View file

@ -6,7 +6,7 @@ import (
"testing" "testing"
"github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@ -105,7 +105,7 @@ func TestAddNetworkFee(t *testing.T) {
}} }}
require.NoError(t, c.AddNetworkFee(tx, 10, accs[0])) require.NoError(t, c.AddNetworkFee(tx, 10, accs[0]))
require.NoError(t, accs[0].SignTx(tx)) require.NoError(t, accs[0].SignTx(tx))
cFee, _ := core.CalculateNetworkFee(accs[0].Contract.Script) cFee, _ := fee.Calculate(accs[0].Contract.Script)
require.Equal(t, int64(io.GetVarSize(tx))*feePerByte+cFee+10, tx.NetworkFee) require.Equal(t, int64(io.GetVarSize(tx))*feePerByte+cFee+10, tx.NetworkFee)
}) })
@ -129,8 +129,8 @@ func TestAddNetworkFee(t *testing.T) {
require.NoError(t, accs[0].SignTx(tx)) require.NoError(t, accs[0].SignTx(tx))
require.NoError(t, accs[1].SignTx(tx)) require.NoError(t, accs[1].SignTx(tx))
require.NoError(t, accs[2].SignTx(tx)) require.NoError(t, accs[2].SignTx(tx))
cFee, _ := core.CalculateNetworkFee(accs[0].Contract.Script) cFee, _ := fee.Calculate(accs[0].Contract.Script)
cFeeM, _ := core.CalculateNetworkFee(accs[1].Contract.Script) cFeeM, _ := fee.Calculate(accs[1].Contract.Script)
require.Equal(t, int64(io.GetVarSize(tx))*feePerByte+cFee+cFeeM+10, tx.NetworkFee) require.Equal(t, int64(io.GetVarSize(tx))*feePerByte+cFee+cFeeM+10, tx.NetworkFee)
}) })
t.Run("Contract", func(t *testing.T) { t.Run("Contract", func(t *testing.T) {

View file

@ -19,6 +19,7 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
@ -787,7 +788,7 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
addNetworkFee := func(tx *transaction.Transaction) { addNetworkFee := func(tx *transaction.Transaction) {
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := core.CalculateNetworkFee(acc0.Contract.Script) netFee, sizeDelta := fee.Calculate(acc0.Contract.Script)
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
tx.NetworkFee += int64(size) * chain.FeePerByte() tx.NetworkFee += int64(size) * chain.FeePerByte()