Compare commits

...

2 commits
master ... sale

Author SHA1 Message Date
AnnaShaleva
e13816f3fd core: handle empty MPT batch properly
It's OK to have it.
2021-10-27 18:36:40 +03:00
AnnaShaleva
e3443b82a4 *: remove fees logic 2021-10-27 17:48:31 +03:00
19 changed files with 23 additions and 158 deletions

View file

@ -1818,18 +1818,6 @@ func (bc *Blockchain) verifyAndPoolTx(t *transaction.Transaction, pool *mempool.
if size > transaction.MaxTransactionSize {
return fmt.Errorf("%w: (%d > MaxTransactionSize %d)", ErrTxTooBig, size, transaction.MaxTransactionSize)
}
needNetworkFee := int64(size) * bc.FeePerByte()
if bc.P2PSigExtensionsEnabled() {
attrs := t.GetAttributes(transaction.NotaryAssistedT)
if len(attrs) != 0 {
na := attrs[0].Value.(*transaction.NotaryAssisted)
needNetworkFee += (int64(na.NKeys) + 1) * transaction.NotaryServiceFeePerKey
}
}
netFee := t.NetworkFee - needNetworkFee
if netFee < 0 {
return fmt.Errorf("%w: net fee is %v, need %v", ErrTxSmallNetworkFee, t.NetworkFee, needNetworkFee)
}
// check that current tx wasn't included in the conflicts attributes of some other transaction which is already in the chain
if err := bc.dao.HasTransaction(t.Hash()); err != nil {
switch {
@ -2129,15 +2117,10 @@ func (bc *Blockchain) VerifyWitness(h util.Uint160, c hash.Hashable, w *transact
// verifyHashAgainstScript verifies given hash against the given witness and returns the amount of GAS consumed.
func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transaction.Witness, interopCtx *interop.Context, gas int64) (int64, error) {
gasPolicy := bc.contracts.Policy.GetMaxVerificationGas(interopCtx.DAO)
if gas > gasPolicy {
gas = gasPolicy
}
vm := interopCtx.SpawnVM()
vm.SetPriceGetter(interopCtx.GetPrice)
vm.LoadToken = contract.LoadToken(interopCtx)
vm.GasLimit = gas
vm.GasLimit = -1
if err := bc.InitVerificationVM(vm, interopCtx.GetContract, hash, witness); err != nil {
return 0, err
}
@ -2172,21 +2155,12 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa
// Golang implementation of VerifyWitnesses method in C# (https://github.com/neo-project/neo/blob/master/neo/SmartContract/Helper.cs#L87).
func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *block.Block, isPartialTx bool) error {
interopCtx := bc.newInteropContext(trigger.Verification, bc.dao, block, t)
gasLimit := t.NetworkFee - int64(t.Size())*bc.FeePerByte()
if bc.P2PSigExtensionsEnabled() {
attrs := t.GetAttributes(transaction.NotaryAssistedT)
if len(attrs) != 0 {
na := attrs[0].Value.(*transaction.NotaryAssisted)
gasLimit -= (int64(na.NKeys) + 1) * transaction.NotaryServiceFeePerKey
}
}
for i := range t.Signers {
gasConsumed, err := bc.verifyHashAgainstScript(t.Signers[i].Account, &t.Scripts[i], interopCtx, gasLimit)
_, err := bc.verifyHashAgainstScript(t.Signers[i].Account, &t.Scripts[i], interopCtx, -1)
if err != nil &&
!(i == 0 && isPartialTx && errors.Is(err, ErrInvalidSignature)) { // it's OK for partially-filled transaction with dummy first witness.
return fmt.Errorf("witness #%d: %w", i, err)
}
gasLimit -= gasConsumed
}
return nil

View file

@ -12,23 +12,16 @@ const ECDSAVerifyPrice = 1 << 15
// Calculate returns network fee for transaction.
func Calculate(base int64, script []byte) (int64, int) {
var (
netFee int64
size int
)
var size int
if vm.IsSignatureContract(script) {
size += 67 + io.GetVarSize(script)
netFee += Opcode(base, opcode.PUSHDATA1, opcode.PUSHDATA1) + base*ECDSAVerifyPrice
} else if m, pubs, ok := vm.ParseMultiSigContract(script); ok {
n := len(pubs)
} else if m, _, ok := vm.ParseMultiSigContract(script); ok {
sizeInv := 66 * m
size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script)
netFee += calculateMultisig(base, m) + calculateMultisig(base, n)
netFee += base * ECDSAVerifyPrice * int64(n)
} /*else {
// We can support more contract types in the future.
}*/
return netFee, size
return 0, size
}
func calculateMultisig(base int64, n int) int64 {

View file

@ -29,7 +29,7 @@ import (
const (
// DefaultBaseExecFee specifies default multiplier for opcode and syscall prices.
DefaultBaseExecFee = 30
DefaultBaseExecFee = 30 // TODO: still 30 in C#, but it's unused or multiplied by 0, so keep it as is.
)
// Context represents context in which interops are executed.
@ -271,9 +271,6 @@ func (ic *Context) SyscallHandler(_ *vm.VM, id uint32) error {
if !cf.Has(f.RequiredFlags) {
return fmt.Errorf("missing call flags: %05b vs %05b", cf, f.RequiredFlags)
}
if !ic.VM.AddGas(f.Price * ic.BaseExecFee()) {
return errors.New("insufficient amount of gas")
}
return f.Func(ic)
}

View file

@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@ -20,9 +19,6 @@ func ECDSASecp256r1CheckMultisig(ic *interop.Context) error {
if err != nil {
return fmt.Errorf("wrong parameters: %w", err)
}
if !ic.VM.AddGas(ic.BaseExecFee() * fee.ECDSAVerifyPrice * int64(len(pkeys))) {
return errors.New("gas limit exceeded")
}
sigs, err := ic.VM.Estack().PopSigElements()
if err != nil {
return fmt.Errorf("wrong parameters: %w", err)

View file

@ -115,20 +115,6 @@ func putWithContext(ic *interop.Context, stc *StorageContext, key []byte, value
if stc.ReadOnly {
return errors.New("StorageContext is read only")
}
si := ic.DAO.GetStorageItem(stc.ID, key)
sizeInc := len(value)
if si == nil {
sizeInc = len(key) + len(value)
} else if len(value) != 0 {
if len(value) <= len(si) {
sizeInc = (len(value)-1)/4 + 1
} else if len(si) != 0 {
sizeInc = (len(si)-1)/4 + 1 + len(value) - len(si)
}
}
if !ic.VM.AddGas(int64(sizeInc) * ic.Chain.GetPolicer().GetStoragePrice()) {
return errGasLimitExceeded
}
return ic.DAO.PutStorageItem(stc.ID, key, value)
}

View file

@ -43,6 +43,9 @@ func (b *Batch) Add(key []byte, value []byte) {
// and won't strip the resulting branch node.
// However it is used mostly after the block processing to update MPT and error is not expected.
func (t *Trie) PutBatch(b Batch) (int, error) {
if len(b.kv) == 0 {
return 0, nil
}
r, n, err := t.putBatch(b.kv)
t.root = r
return n, err

View file

@ -41,11 +41,6 @@ func Call(ic *interop.Context) error {
return fmt.Errorf("missing call flags for native %d `%s` operation call: %05b vs %05b",
version, m.MD.Name, ic.VM.Context().GetCallFlags(), m.RequiredFlags)
}
invokeFee := m.CPUFee*ic.Chain.GetPolicer().GetBaseExecFee() +
m.StorageFee*ic.Chain.GetPolicer().GetStoragePrice()
if !ic.VM.AddGas(invokeFee) {
return errors.New("gas limit exceeded")
}
ctx := ic.VM.Context()
args := make([]stackitem.Item, len(m.MD.Parameters))
for i := range args {

View file

@ -42,7 +42,7 @@ const (
prefixContract = 8
defaultMinimumDeploymentFee = 10_00000000
defaultMinimumDeploymentFee = 0
contractDeployNotificationName = "Deploy"
contractUpdateNotificationName = "Update"
contractDestroyNotificationName = "Destroy"
@ -195,16 +195,6 @@ func (m *Management) getNefAndManifestFromItems(ic *interop.Context, args []stac
return nil, nil, fmt.Errorf("invalid manifest: %w", err)
}
gas := ic.Chain.GetPolicer().GetStoragePrice() * int64(len(nefBytes)+len(manifestBytes))
if isDeploy {
fee := m.GetMinimumDeploymentFee(ic.DAO)
if fee > gas {
gas = fee
}
}
if !ic.VM.AddGas(gas) {
return nil, nil, errGasLimitExceeded
}
var resManifest *manifest.Manifest
var resNef *nef.File
if nefBytes != nil {

View file

@ -100,13 +100,6 @@ func (g *GAS) OnPersist(ic *interop.Context) error {
absAmount := big.NewInt(tx.SystemFee + tx.NetworkFee)
g.burn(ic, tx.Sender(), absAmount)
}
validators := g.NEO.GetNextBlockValidatorsInternal()
primary := validators[ic.Block.PrimaryIndex].GetScriptHash()
var netFee int64
for _, tx := range ic.Block.Transactions {
netFee += tx.NetworkFee
}
g.mint(ic, primary, big.NewInt(int64(netFee)), false)
return nil
}

View file

@ -313,11 +313,7 @@ func (n *NEO) OnPersist(ic *interop.Context) error {
// PostPersist implements Contract interface.
func (n *NEO) PostPersist(ic *interop.Context) error {
gas := n.GetGASPerBlock(ic.DAO, ic.Block.Index)
pubs := n.GetCommitteeMembers()
committeeSize := len(ic.Chain.GetConfig().StandbyCommittee)
index := int(ic.Block.Index) % committeeSize
committeeReward := new(big.Int).Mul(gas, big.NewInt(committeeRewardRatio))
n.GAS.mint(ic, pubs[index].GetScriptHash(), committeeReward.Div(committeeReward, big.NewInt(100)), false)
if ShouldUpdateCommittee(ic.Block.Index, ic.Chain) {
var voterReward = big.NewInt(voterRewardRatio)
@ -437,21 +433,16 @@ func (n *NEO) distributeGas(ic *interop.Context, h util.Uint160, acc *state.NEOB
if ic.Block == nil || ic.Block.Index == 0 || ic.Block.Index == acc.BalanceHeight {
return nil
}
gen, err := n.calculateBonus(ic.DAO, acc.VoteTo, &acc.Balance, acc.BalanceHeight, ic.Block.Index)
if err != nil {
return err
}
acc.BalanceHeight = ic.Block.Index
// Must store acc before GAS distribution to fix acc's BalanceHeight value in the storage for
// further acc's queries from `onNEP17Payment` if so, see https://github.com/nspcc-dev/neo-go/pull/2181.
key := makeAccountKey(h)
err = ic.DAO.PutStorageItem(n.ID, key, acc.Bytes())
err := ic.DAO.PutStorageItem(n.ID, key, acc.Bytes())
if err != nil {
return fmt.Errorf("failed to store acc before gas distribution: %w", err)
}
n.GAS.mint(ic, h, gen, true)
return nil
}
@ -690,9 +681,6 @@ func (n *NEO) registerCandidate(ic *interop.Context, args []stackitem.Item) stac
} else if !ok {
return stackitem.NewBool(false)
}
if !ic.VM.AddGas(n.getRegisterPriceInternal(ic.DAO)) {
panic("insufficient gas")
}
err = n.RegisterCandidateInternal(ic, pub)
return stackitem.NewBool(err == nil)
}

View file

@ -74,7 +74,7 @@ func newNEP17Native(name string, id int32) *nep17TokenNative {
append(transferParams, manifest.NewParameter("data", smartcontract.AnyType))...,
)
md = newMethodAndPrice(n.Transfer, 1<<17, callflag.States|callflag.AllowCall|callflag.AllowNotify)
md.StorageFee = 50
md.StorageFee = 0
n.AddMethod(md, desc)
n.AddEvent("Transfer", transferParams...)
@ -311,7 +311,7 @@ func newDescriptor(name string, ret smartcontract.ParamType, ps ...manifest.Para
func newMethodAndPrice(f interop.Method, cpuFee int64, flags callflag.CallFlag) *interop.MethodAndPrice {
return &interop.MethodAndPrice{
Func: f,
CPUFee: cpuFee,
CPUFee: 0,
RequiredFlags: flags,
}
}

View file

@ -154,13 +154,6 @@ func (n *Notary) OnPersist(ic *interop.Context) error {
}
}
}
if nFees == 0 {
return nil
}
singleReward := calculateNotaryReward(nFees, len(notaries))
for _, notary := range notaries {
n.GAS.mint(ic, notary.GetScriptHash(), singleReward, false)
}
return nil
}

View file

@ -156,9 +156,6 @@ func (o *Oracle) PostPersist(ic *interop.Context) error {
o.requestPriceChanged.Store(false)
}
var nodes keys.PublicKeys
var reward []big.Int
single := big.NewInt(p)
var removedIDs []uint64
orc, _ := o.Module.Load().(services.Oracle)
@ -197,22 +194,6 @@ func (o *Oracle) PostPersist(ic *interop.Context) error {
if err != nil {
return err
}
if nodes == nil {
nodes, err = o.GetOracleNodes(ic.DAO)
if err != nil {
return err
}
reward = make([]big.Int, len(nodes))
}
if len(reward) > 0 {
index := resp.ID % uint64(len(nodes))
reward[index].Add(&reward[index], single)
}
}
for i := range reward {
o.GAS.mint(ic, nodes[i].GetScriptHash(), &reward[i], false)
}
if len(removedIDs) != 0 && orc != nil {
@ -317,9 +298,6 @@ func (o *Oracle) request(ic *interop.Context, args []stackitem.Item) stackitem.I
if err != nil {
panic(err)
}
if !ic.VM.AddGas(o.getPriceInternal(ic.DAO)) {
panic("insufficient gas")
}
if err := o.RequestInternal(ic, url, filter, cb, userData, gas); err != nil {
panic(err)
}
@ -331,18 +309,14 @@ func (o *Oracle) RequestInternal(ic *interop.Context, url string, filter *string
if len(url) > maxURLLength || (filter != nil && len(*filter) > maxFilterLength) || len(cb) > maxCallbackLength || !gas.IsInt64() {
return ErrBigArgument
}
if gas.Int64() < MinimumResponseGas {
if gas.Int64() < MinimumResponseGas { // TODO: this constraint is still in the C#, although we don't use this GAS
return ErrLowResponseGas
}
if strings.HasPrefix(cb, "_") {
return errors.New("disallowed callback method (starts with '_')")
}
if !ic.VM.AddGas(gas.Int64()) {
return ErrNotEnoughGas
}
callingHash := ic.VM.GetCallingScriptHash()
o.GAS.mint(ic, o.Hash, gas, false)
si := ic.DAO.GetStorageItem(o.ID, prefixRequestID)
itemID := bigint.FromBytes(si)
id := itemID.Uint64()

View file

@ -22,7 +22,7 @@ const (
policyContractID = -7
defaultExecFeeFactor = interop.DefaultBaseExecFee
defaultFeePerByte = 1000
defaultFeePerByte = 1000 // TODO: it is still in the storage, but GetFeePerByte() returns 0 in C#.
defaultMaxVerificationGas = 1_50000000
// DefaultStoragePrice is the price to pay for 1 byte of storage.
DefaultStoragePrice = 100000
@ -189,6 +189,7 @@ func (p *Policy) getFeePerByte(ic *interop.Context, _ []stackitem.Item) stackite
// GetFeePerByteInternal returns required transaction's fee per byte.
func (p *Policy) GetFeePerByteInternal(dao dao.DAO) int64 {
return 0
p.lock.RLock()
defer p.lock.RUnlock()
if p.isValid {
@ -267,6 +268,7 @@ func (p *Policy) getStoragePrice(ic *interop.Context, _ []stackitem.Item) stacki
// GetStoragePriceInternal returns current execution fee factor.
func (p *Policy) GetStoragePriceInternal(d dao.DAO) int64 {
// TODO: this method still returns non-zero value (unlike getFeePerByte)
p.lock.RLock()
defer p.lock.RUnlock()
if p.isValid {

View file

@ -89,7 +89,7 @@ func TestFeePerByte(t *testing.T) {
require.Equal(t, 1000, int(n))
})
testGetSet(t, chain, chain.contracts.Policy.Hash, "FeePerByte", 1000, 0, 100_000_000)
testGetSet(t, chain, chain.contracts.Policy.Hash, "FeePerByte", 0, 0, 100_000_000)
}
func TestExecFeeFactor(t *testing.T) {

View file

@ -872,7 +872,6 @@ func (c *Client) AddNetworkFee(tx *transaction.Transaction, extraFee int64, accs
if r == 0 {
return fmt.Errorf("signer #%d: `verify` returned `false`", i)
}
tx.NetworkFee += res.GasConsumed
size += io.GetVarSize([]byte{}) * 2 // both scripts are empty
continue
}
@ -884,15 +883,9 @@ func (c *Client) AddNetworkFee(tx *transaction.Transaction, extraFee int64, accs
return fmt.Errorf("can't get `ExecFeeFactor`: %w", err)
}
}
netFee, sizeDelta := fee.Calculate(ef, accs[i].Contract.Script)
tx.NetworkFee += netFee
_, sizeDelta := fee.Calculate(ef, accs[i].Contract.Script)
size += sizeDelta
}
fee, err := c.GetFeePerByte()
if err != nil {
return err
}
tx.NetworkFee += int64(size)*fee + extraFee
return nil
}

View file

@ -600,8 +600,7 @@ func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *re
}
size := len(hashablePart) + io.GetVarSize(len(tx.Signers))
var (
ef int64
netFee int64
ef int64
)
for i, signer := range tx.Signers {
var verificationScript []byte
@ -641,7 +640,6 @@ func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *re
cause := errors.New("`verify` method returned `false` on stack")
return 0, response.NewRPCError(verificationErr, cause.Error(), cause)
}
netFee += res.GasConsumed
size += io.GetVarSize([]byte{}) + // verification script is empty (contract-based witness)
io.GetVarSize(tx.Scripts[i].InvocationScript) // invocation script might not be empty (args for `verify`)
continue
@ -650,13 +648,10 @@ func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *re
if ef == 0 {
ef = s.chain.GetPolicer().GetBaseExecFee()
}
fee, sizeDelta := fee.Calculate(ef, verificationScript)
netFee += fee
_, sizeDelta := fee.Calculate(ef, verificationScript)
size += sizeDelta
}
fee := s.chain.GetPolicer().FeePerByte()
netFee += int64(size) * fee
return result.NetworkFee{Value: netFee}, nil
return result.NetworkFee{Value: 0}, nil
}
// getApplicationLog returns the contract log based on the specified txid or blockid.

View file

@ -119,7 +119,7 @@ func (o *Oracle) CreateResponseTx(gasForResponse int64, vub uint32, resp *transa
tx.NetworkFee += netFee
size += sizeDelta
currNetFee := tx.NetworkFee + int64(size)*o.Chain.FeePerByte()
currNetFee := tx.NetworkFee + int64(size)*o.Chain.FeePerByte() // TODO: this logic remains the same in C#
if currNetFee > gasForResponse {
attrSize := io.GetVarSize(tx.Attributes)
resp.Code = transaction.InsufficientFunds

View file

@ -535,13 +535,6 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
}
}()
if v.getPrice != nil && ctx.ip < len(ctx.prog) {
v.gasConsumed += v.getPrice(op, parameter)
if v.GasLimit >= 0 && v.gasConsumed > v.GasLimit {
panic("gas limit is exceeded")
}
}
if op <= opcode.PUSHINT256 {
v.estack.PushItem(stackitem.NewBigInteger(bigint.FromBytes(parameter)))
return