diff --git a/pkg/compiler/native_test.go b/pkg/compiler/native_test.go index ae99a46ea..af49507c9 100644 --- a/pkg/compiler/native_test.go +++ b/pkg/compiler/native_test.go @@ -110,15 +110,19 @@ func TestNativeHelpersCompile(t *testing.T) { {"getCommittee", nil}, {"getGasPerBlock", nil}, {"getNextBlockValidators", nil}, + {"getRegisterPrice", nil}, {"registerCandidate", []string{pub}}, {"setGasPerBlock", []string{"1"}}, + {"setRegisterPrice", []string{"10"}}, {"vote", []string{u160, pub}}, {"unclaimedGas", []string{u160, "123"}}, {"unregisterCandidate", []string{pub}}, }, nep17TestCases...)) runNativeTestCases(t, cs.GAS.ContractMD, "gas", nep17TestCases) runNativeTestCases(t, cs.Oracle.ContractMD, "oracle", []nativeTestCase{ + {"getPrice", nil}, {"request", []string{`"url"`, "nil", `"callback"`, "nil", "123"}}, + {"setPrice", []string{"10"}}, }) runNativeTestCases(t, cs.Designate.ContractMD, "roles", []nativeTestCase{ {"designateAsRole", []string{"1", "[]interop.PublicKey{}"}}, diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 251497e9c..59f6c3a5e 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -1029,7 +1029,7 @@ func TestVerifyTx(t *testing.T) { fee.Opcode(bc.GetBaseExecFee(), // Notary verification script opcode.PUSHDATA1, opcode.RET, // invocation script opcode.PUSH0, opcode.SYSCALL, opcode.RET) + // Neo.Native.Call - native.NotaryVerificationPrice // Notary witness verification price + native.NotaryVerificationPrice*bc.GetBaseExecFee() // Notary witness verification price tx.Scripts = []transaction.Witness{ { InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, make([]byte, 64, 64)...), diff --git a/pkg/core/interop/context.go b/pkg/core/interop/context.go index 121cf23d5..6768c5324 100644 --- a/pkg/core/interop/context.go +++ b/pkg/core/interop/context.go @@ -90,7 +90,8 @@ type Method = func(ic *Context, args []stackitem.Item) stackitem.Item type MethodAndPrice struct { Func Method MD *manifest.Method - Price int64 + CPUFee int64 + StorageFee int64 SyscallOffset int RequiredFlags callflag.CallFlag } diff --git a/pkg/core/native/designate.go b/pkg/core/native/designate.go index 1186d6d7a..c70e70640 100644 --- a/pkg/core/native/designate.go +++ b/pkg/core/native/designate.go @@ -92,13 +92,13 @@ func newDesignate(p2pSigExtensionsEnabled bool) *Designate { desc := newDescriptor("getDesignatedByRole", smartcontract.ArrayType, manifest.NewParameter("role", smartcontract.IntegerType), manifest.NewParameter("index", smartcontract.IntegerType)) - md := newMethodAndPrice(s.getDesignatedByRole, 1000000, callflag.ReadStates) + md := newMethodAndPrice(s.getDesignatedByRole, 1<<15, callflag.ReadStates) s.AddMethod(md, desc) desc = newDescriptor("designateAsRole", smartcontract.VoidType, manifest.NewParameter("role", smartcontract.IntegerType), manifest.NewParameter("nodes", smartcontract.ArrayType)) - md = newMethodAndPrice(s.designateAsRole, 0, callflag.States) + md = newMethodAndPrice(s.designateAsRole, 1<<15, callflag.States) s.AddMethod(md, desc) return s diff --git a/pkg/core/native/interop.go b/pkg/core/native/interop.go index 99853eded..084a3f2de 100644 --- a/pkg/core/native/interop.go +++ b/pkg/core/native/interop.go @@ -34,8 +34,9 @@ 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) } - // Native contract prices are not multiplied by `BaseExecFee`. - if !ic.VM.AddGas(m.Price) { + 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() diff --git a/pkg/core/native/ledger.go b/pkg/core/native/ledger.go index 4c76da1d5..88e86f87e 100644 --- a/pkg/core/native/ledger.go +++ b/pkg/core/native/ledger.go @@ -42,32 +42,32 @@ func newLedger() *Ledger { defer l.UpdateHash() desc := newDescriptor("currentHash", smartcontract.Hash256Type) - md := newMethodAndPrice(l.currentHash, 1000000, callflag.ReadStates) + md := newMethodAndPrice(l.currentHash, 1<<15, callflag.ReadStates) l.AddMethod(md, desc) desc = newDescriptor("currentIndex", smartcontract.IntegerType) - md = newMethodAndPrice(l.currentIndex, 1000000, callflag.ReadStates) + md = newMethodAndPrice(l.currentIndex, 1<<15, callflag.ReadStates) l.AddMethod(md, desc) desc = newDescriptor("getBlock", smartcontract.ArrayType, manifest.NewParameter("indexOrHash", smartcontract.ByteArrayType)) - md = newMethodAndPrice(l.getBlock, 1000000, callflag.ReadStates) + md = newMethodAndPrice(l.getBlock, 1<<15, callflag.ReadStates) l.AddMethod(md, desc) desc = newDescriptor("getTransaction", smartcontract.ArrayType, manifest.NewParameter("hash", smartcontract.Hash256Type)) - md = newMethodAndPrice(l.getTransaction, 1000000, callflag.ReadStates) + md = newMethodAndPrice(l.getTransaction, 1<<15, callflag.ReadStates) l.AddMethod(md, desc) desc = newDescriptor("getTransactionHeight", smartcontract.IntegerType, manifest.NewParameter("hash", smartcontract.Hash256Type)) - md = newMethodAndPrice(l.getTransactionHeight, 1000000, callflag.ReadStates) + md = newMethodAndPrice(l.getTransactionHeight, 1<<15, callflag.ReadStates) l.AddMethod(md, desc) desc = newDescriptor("getTransactionFromBlock", smartcontract.ArrayType, manifest.NewParameter("blockIndexOrHash", smartcontract.ByteArrayType), manifest.NewParameter("txIndex", smartcontract.IntegerType)) - md = newMethodAndPrice(l.getTransactionFromBlock, 2000000, callflag.ReadStates) + md = newMethodAndPrice(l.getTransactionFromBlock, 1<<16, callflag.ReadStates) l.AddMethod(md, desc) return l diff --git a/pkg/core/native/management.go b/pkg/core/native/management.go index 2e74518e8..75eed6978 100644 --- a/pkg/core/native/management.go +++ b/pkg/core/native/management.go @@ -69,7 +69,7 @@ func newManagement() *Management { desc := newDescriptor("getContract", smartcontract.ArrayType, manifest.NewParameter("hash", smartcontract.Hash160Type)) - md := newMethodAndPrice(m.getContract, 1000000, callflag.ReadStates) + md := newMethodAndPrice(m.getContract, 1<<15, callflag.ReadStates) m.AddMethod(md, desc) desc = newDescriptor("deploy", smartcontract.ArrayType, @@ -99,16 +99,16 @@ func newManagement() *Management { m.AddMethod(md, desc) desc = newDescriptor("destroy", smartcontract.VoidType) - md = newMethodAndPrice(m.destroy, 1000000, callflag.States|callflag.AllowNotify) + md = newMethodAndPrice(m.destroy, 1<<15, callflag.States|callflag.AllowNotify) m.AddMethod(md, desc) desc = newDescriptor("getMinimumDeploymentFee", smartcontract.IntegerType) - md = newMethodAndPrice(m.getMinimumDeploymentFee, 100_0000, callflag.ReadStates) + md = newMethodAndPrice(m.getMinimumDeploymentFee, 1<<15, callflag.ReadStates) m.AddMethod(md, desc) desc = newDescriptor("setMinimumDeploymentFee", smartcontract.VoidType, manifest.NewParameter("value", smartcontract.IntegerType)) - md = newMethodAndPrice(m.setMinimumDeploymentFee, 300_0000, callflag.States) + md = newMethodAndPrice(m.setMinimumDeploymentFee, 1<<15, callflag.States) m.AddMethod(md, desc) hashParam := manifest.NewParameter("Hash", smartcontract.Hash160Type) diff --git a/pkg/core/native/name_service.go b/pkg/core/native/name_service.go index dbaefde72..4edb45155 100644 --- a/pkg/core/native/name_service.go +++ b/pkg/core/native/name_service.go @@ -104,27 +104,27 @@ func newNameService() *NameService { desc := newDescriptor("addRoot", smartcontract.VoidType, manifest.NewParameter("root", smartcontract.StringType)) - md := newMethodAndPrice(n.addRoot, 3000000, callflag.States) + md := newMethodAndPrice(n.addRoot, 1<<15, callflag.States) n.AddMethod(md, desc) desc = newDescriptor("setPrice", smartcontract.VoidType, manifest.NewParameter("price", smartcontract.IntegerType)) - md = newMethodAndPrice(n.setPrice, 3000000, callflag.States) + md = newMethodAndPrice(n.setPrice, 1<<15, callflag.States) n.AddMethod(md, desc) desc = newDescriptor("getPrice", smartcontract.IntegerType) - md = newMethodAndPrice(n.getPrice, 1000000, callflag.ReadStates) + md = newMethodAndPrice(n.getPrice, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("isAvailable", smartcontract.BoolType, manifest.NewParameter("name", smartcontract.StringType)) - md = newMethodAndPrice(n.isAvailable, 1000000, callflag.ReadStates) + md = newMethodAndPrice(n.isAvailable, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("register", smartcontract.BoolType, manifest.NewParameter("name", smartcontract.StringType), manifest.NewParameter("owner", smartcontract.Hash160Type)) - md = newMethodAndPrice(n.register, 1000000, callflag.States) + md = newMethodAndPrice(n.register, 1<<15, callflag.States) n.AddMethod(md, desc) desc = newDescriptor("renew", smartcontract.IntegerType, @@ -135,32 +135,34 @@ func newNameService() *NameService { desc = newDescriptor("setAdmin", smartcontract.VoidType, manifest.NewParameter("name", smartcontract.StringType), manifest.NewParameter("admin", smartcontract.Hash160Type)) - md = newMethodAndPrice(n.setAdmin, 3000000, callflag.States) + md = newMethodAndPrice(n.setAdmin, 1<<15, callflag.States) + md.StorageFee = 20 n.AddMethod(md, desc) desc = newDescriptor("setRecord", smartcontract.VoidType, manifest.NewParameter("name", smartcontract.StringType), manifest.NewParameter("type", smartcontract.IntegerType), manifest.NewParameter("data", smartcontract.StringType)) - md = newMethodAndPrice(n.setRecord, 30000000, callflag.States) + md = newMethodAndPrice(n.setRecord, 1<<15, callflag.States) + md.StorageFee = 200 n.AddMethod(md, desc) desc = newDescriptor("getRecord", smartcontract.StringType, manifest.NewParameter("name", smartcontract.StringType), manifest.NewParameter("type", smartcontract.IntegerType)) - md = newMethodAndPrice(n.getRecord, 1000000, callflag.ReadStates) + md = newMethodAndPrice(n.getRecord, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("deleteRecord", smartcontract.VoidType, manifest.NewParameter("name", smartcontract.StringType), manifest.NewParameter("type", smartcontract.IntegerType)) - md = newMethodAndPrice(n.deleteRecord, 1000000, callflag.States) + md = newMethodAndPrice(n.deleteRecord, 1<<15, callflag.States) n.AddMethod(md, desc) desc = newDescriptor("resolve", smartcontract.StringType, manifest.NewParameter("name", smartcontract.StringType), manifest.NewParameter("type", smartcontract.IntegerType)) - md = newMethodAndPrice(n.resolve, 3000000, callflag.ReadStates) + md = newMethodAndPrice(n.resolve, 1<<17, callflag.ReadStates) n.AddMethod(md, desc) return n diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index 543b09842..c4c9c51cf 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -37,6 +37,9 @@ type NEO struct { gasPerBlock atomic.Value gasPerBlockChanged atomic.Value + registerPrice atomic.Value + registerPriceChanged atomic.Value + votesChanged atomic.Value nextValidators atomic.Value validators atomic.Value @@ -53,6 +56,8 @@ const ( neoContractID = -5 // NEOTotalSupply is the total amount of NEO in the system. NEOTotalSupply = 100000000 + // DefaultRegisterPrice is default price for candidate register. + DefaultRegisterPrice = 1000 * GASFactor // prefixCandidate is a prefix used to store validator's data. prefixCandidate = 33 // prefixVotersCount is a prefix for storing total amount of NEO of voters. @@ -62,8 +67,10 @@ const ( // voterRewardFactor is a factor by which voter reward per committee is multiplied // to make calculations more precise. voterRewardFactor = 100_000_000 - // prefixGasPerBlock is a prefix for storing amount of GAS generated per block. + // prefixGASPerBlock is a prefix for storing amount of GAS generated per block. prefixGASPerBlock = 29 + // prefixRegisterPrice is a prefix for storing candidate register price. + prefixRegisterPrice = 13 // effectiveVoterTurnout represents minimal ratio of total supply to total amount voted value // which is require to use non-standby validators. effectiveVoterTurnout = 5 @@ -107,48 +114,58 @@ func newNEO() *NEO { n.validators.Store(keys.PublicKeys(nil)) n.committee.Store(keysWithVotes(nil)) n.committeeHash.Store(util.Uint160{}) + n.registerPriceChanged.Store(true) desc := newDescriptor("unclaimedGas", smartcontract.IntegerType, manifest.NewParameter("account", smartcontract.Hash160Type), manifest.NewParameter("end", smartcontract.IntegerType)) - md := newMethodAndPrice(n.unclaimedGas, 3000000, callflag.ReadStates) + md := newMethodAndPrice(n.unclaimedGas, 1<<17, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("registerCandidate", smartcontract.BoolType, manifest.NewParameter("pubkey", smartcontract.ByteArrayType)) - md = newMethodAndPrice(n.registerCandidate, 1000_00000000, callflag.States) + md = newMethodAndPrice(n.registerCandidate, 0, callflag.States) n.AddMethod(md, desc) desc = newDescriptor("unregisterCandidate", smartcontract.BoolType, manifest.NewParameter("pubkey", smartcontract.ByteArrayType)) - md = newMethodAndPrice(n.unregisterCandidate, 5000000, callflag.States) + md = newMethodAndPrice(n.unregisterCandidate, 1<<16, callflag.States) n.AddMethod(md, desc) desc = newDescriptor("vote", smartcontract.BoolType, manifest.NewParameter("account", smartcontract.Hash160Type), manifest.NewParameter("voteTo", smartcontract.ByteArrayType)) - md = newMethodAndPrice(n.vote, 5000000, callflag.States) + md = newMethodAndPrice(n.vote, 1<<16, callflag.States) n.AddMethod(md, desc) desc = newDescriptor("getCandidates", smartcontract.ArrayType) - md = newMethodAndPrice(n.getCandidatesCall, 100000000, callflag.ReadStates) + md = newMethodAndPrice(n.getCandidatesCall, 1<<22, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("getCommittee", smartcontract.ArrayType) - md = newMethodAndPrice(n.getCommittee, 100000000, callflag.ReadStates) + md = newMethodAndPrice(n.getCommittee, 1<<22, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("getNextBlockValidators", smartcontract.ArrayType) - md = newMethodAndPrice(n.getNextBlockValidators, 100000000, callflag.ReadStates) + md = newMethodAndPrice(n.getNextBlockValidators, 1<<22, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("getGasPerBlock", smartcontract.IntegerType) - md = newMethodAndPrice(n.getGASPerBlock, 100_0000, callflag.ReadStates) + md = newMethodAndPrice(n.getGASPerBlock, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("setGasPerBlock", smartcontract.VoidType, manifest.NewParameter("gasPerBlock", smartcontract.IntegerType)) - md = newMethodAndPrice(n.setGASPerBlock, 500_0000, callflag.States) + md = newMethodAndPrice(n.setGASPerBlock, 1<<15, callflag.States) + n.AddMethod(md, desc) + + desc = newDescriptor("getRegisterPrice", smartcontract.IntegerType) + md = newMethodAndPrice(n.getRegisterPrice, 1<<15, callflag.ReadStates) + n.AddMethod(md, desc) + + desc = newDescriptor("setRegisterPrice", smartcontract.VoidType, + manifest.NewParameter("registerPrice", smartcontract.IntegerType)) + md = newMethodAndPrice(n.setRegisterPrice, 1<<15, callflag.States) n.AddMethod(md, desc) return n @@ -196,6 +213,12 @@ func (n *NEO) Initialize(ic *interop.Context) error { return err } + err = setIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}, DefaultRegisterPrice) + if err != nil { + return err + } + n.registerPrice.Store(int64(DefaultRegisterPrice)) + n.registerPriceChanged.Store(false) return nil } @@ -323,6 +346,12 @@ func (n *NEO) PostPersist(ic *interop.Context) error { n.gasPerBlock.Store(gr) n.gasPerBlockChanged.Store(false) } + + if n.registerPriceChanged.Load().(bool) { + p := getIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}) + n.registerPrice.Store(p) + n.registerPriceChanged.Store(false) + } return nil } @@ -482,6 +511,34 @@ func (n *NEO) SetGASPerBlock(ic *interop.Context, index uint32, gas *big.Int) er return n.putGASRecord(ic.DAO, index, gas) } +func (n *NEO) getRegisterPrice(ic *interop.Context, _ []stackitem.Item) stackitem.Item { + return stackitem.NewBigInteger(big.NewInt(n.getRegisterPriceInternal(ic.DAO))) +} + +func (n *NEO) getRegisterPriceInternal(d dao.DAO) int64 { + if !n.registerPriceChanged.Load().(bool) { + return n.registerPrice.Load().(int64) + } + return getIntWithKey(n.ID, d, []byte{prefixRegisterPrice}) +} + +func (n *NEO) setRegisterPrice(ic *interop.Context, args []stackitem.Item) stackitem.Item { + price := toBigInt(args[0]) + if price.Sign() <= 0 || !price.IsInt64() { + panic("invalid register price") + } + if !n.checkCommittee(ic) { + panic("invalid committee signature") + } + + err := setIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}, price.Int64()) + if err != nil { + panic(err) + } + n.registerPriceChanged.Store(true) + return stackitem.Null{} +} + func (n *NEO) dropCandidateIfZero(d dao.DAO, pub *keys.PublicKey, c *candidate) (bool, error) { if c.Registered || c.Votes.Sign() != 0 { return false, nil @@ -592,6 +649,9 @@ 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) } diff --git a/pkg/core/native/native_nep17.go b/pkg/core/native/native_nep17.go index 2dd171ac3..2d3cde642 100644 --- a/pkg/core/native/native_nep17.go +++ b/pkg/core/native/native_nep17.go @@ -55,12 +55,12 @@ func newNEP17Native(name string, id int32) *nep17TokenNative { n.AddMethod(md, desc) desc = newDescriptor("totalSupply", smartcontract.IntegerType) - md = newMethodAndPrice(n.TotalSupply, 1000000, callflag.ReadStates) + md = newMethodAndPrice(n.TotalSupply, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("balanceOf", smartcontract.IntegerType, manifest.NewParameter("account", smartcontract.Hash160Type)) - md = newMethodAndPrice(n.balanceOf, 1000000, callflag.ReadStates) + md = newMethodAndPrice(n.balanceOf, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) transferParams := []manifest.Parameter{ @@ -71,7 +71,8 @@ func newNEP17Native(name string, id int32) *nep17TokenNative { desc = newDescriptor("transfer", smartcontract.BoolType, append(transferParams, manifest.NewParameter("data", smartcontract.AnyType))..., ) - md = newMethodAndPrice(n.Transfer, 9000000, callflag.States|callflag.AllowCall|callflag.AllowNotify) + md = newMethodAndPrice(n.Transfer, 1<<17, callflag.States|callflag.AllowCall|callflag.AllowNotify) + md.StorageFee = 50 n.AddMethod(md, desc) n.AddEvent("Transfer", transferParams...) @@ -283,10 +284,10 @@ func newDescriptor(name string, ret smartcontract.ParamType, ps ...manifest.Para } } -func newMethodAndPrice(f interop.Method, price int64, flags callflag.CallFlag) *interop.MethodAndPrice { +func newMethodAndPrice(f interop.Method, cpuFee int64, flags callflag.CallFlag) *interop.MethodAndPrice { return &interop.MethodAndPrice{ Func: f, - Price: price, + CPUFee: cpuFee, RequiredFlags: flags, } } diff --git a/pkg/core/native/nonfungible.go b/pkg/core/native/nonfungible.go index 5d93392c6..49846e313 100644 --- a/pkg/core/native/nonfungible.go +++ b/pkg/core/native/nonfungible.go @@ -77,37 +77,38 @@ func newNonFungible(name string, id int32, symbol string, decimals byte) *nonfun n.AddMethod(md, desc) desc = newDescriptor("totalSupply", smartcontract.IntegerType) - md = newMethodAndPrice(n.totalSupply, 1000000, callflag.ReadStates) + md = newMethodAndPrice(n.totalSupply, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("ownerOf", smartcontract.Hash160Type, manifest.NewParameter("tokenId", smartcontract.ByteArrayType)) - md = newMethodAndPrice(n.OwnerOf, 1000000, callflag.ReadStates) + md = newMethodAndPrice(n.OwnerOf, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("balanceOf", smartcontract.IntegerType, manifest.NewParameter("owner", smartcontract.Hash160Type)) - md = newMethodAndPrice(n.BalanceOf, 1000000, callflag.ReadStates) + md = newMethodAndPrice(n.BalanceOf, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("properties", smartcontract.MapType, manifest.NewParameter("tokenId", smartcontract.ByteArrayType)) - md = newMethodAndPrice(n.Properties, 1000000, callflag.ReadStates) + md = newMethodAndPrice(n.Properties, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("tokens", smartcontract.AnyType) - md = newMethodAndPrice(n.tokens, 1000000, callflag.ReadStates) + md = newMethodAndPrice(n.tokens, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("tokensOf", smartcontract.AnyType, manifest.NewParameter("owner", smartcontract.Hash160Type)) - md = newMethodAndPrice(n.tokensOf, 1000000, callflag.ReadStates) + md = newMethodAndPrice(n.tokensOf, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("transfer", smartcontract.BoolType, manifest.NewParameter("to", smartcontract.Hash160Type), manifest.NewParameter("tokenId", smartcontract.ByteArrayType)) - md = newMethodAndPrice(n.transfer, 9000000, callflag.States|callflag.AllowNotify) + md = newMethodAndPrice(n.transfer, 1<<17, callflag.States|callflag.AllowNotify) + md.StorageFee = 50 n.AddMethod(md, desc) n.AddEvent("Transfer", diff --git a/pkg/core/native/notary.go b/pkg/core/native/notary.go index 8bfeecd68..abf0d2b66 100644 --- a/pkg/core/native/notary.go +++ b/pkg/core/native/notary.go @@ -41,7 +41,7 @@ type Notary struct { const ( notaryContractID = reservedContractID - 1 // NotaryVerificationPrice is the price of `verify` Notary method. - NotaryVerificationPrice = 100_0000 + NotaryVerificationPrice = 1 << 15 // prefixDeposit is a prefix for storing Notary deposits. prefixDeposit = 1 @@ -60,29 +60,29 @@ func newNotary() *Notary { manifest.NewParameter("from", smartcontract.Hash160Type), manifest.NewParameter("amount", smartcontract.IntegerType), manifest.NewParameter("data", smartcontract.AnyType)) - md := newMethodAndPrice(n.onPayment, 100_0000, callflag.States) + md := newMethodAndPrice(n.onPayment, 1<<15, callflag.States) n.AddMethod(md, desc) desc = newDescriptor("lockDepositUntil", smartcontract.BoolType, manifest.NewParameter("address", smartcontract.Hash160Type), manifest.NewParameter("till", smartcontract.IntegerType)) - md = newMethodAndPrice(n.lockDepositUntil, 100_0000, callflag.States) + md = newMethodAndPrice(n.lockDepositUntil, 1<<15, callflag.States) n.AddMethod(md, desc) desc = newDescriptor("withdraw", smartcontract.BoolType, manifest.NewParameter("from", smartcontract.Hash160Type), manifest.NewParameter("to", smartcontract.Hash160Type)) - md = newMethodAndPrice(n.withdraw, 100_0000, callflag.States) + md = newMethodAndPrice(n.withdraw, 1<<15, callflag.States) n.AddMethod(md, desc) desc = newDescriptor("balanceOf", smartcontract.IntegerType, manifest.NewParameter("addr", smartcontract.Hash160Type)) - md = newMethodAndPrice(n.balanceOf, 100_0000, callflag.ReadStates) + md = newMethodAndPrice(n.balanceOf, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("expirationOf", smartcontract.IntegerType, manifest.NewParameter("addr", smartcontract.Hash160Type)) - md = newMethodAndPrice(n.expirationOf, 100_0000, callflag.ReadStates) + md = newMethodAndPrice(n.expirationOf, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("verify", smartcontract.BoolType, @@ -91,12 +91,12 @@ func newNotary() *Notary { n.AddMethod(md, desc) desc = newDescriptor("getMaxNotValidBeforeDelta", smartcontract.IntegerType) - md = newMethodAndPrice(n.getMaxNotValidBeforeDelta, 100_0000, callflag.ReadStates) + md = newMethodAndPrice(n.getMaxNotValidBeforeDelta, 1<<15, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("setMaxNotValidBeforeDelta", smartcontract.VoidType, manifest.NewParameter("value", smartcontract.IntegerType)) - md = newMethodAndPrice(n.setMaxNotValidBeforeDelta, 300_0000, callflag.States) + md = newMethodAndPrice(n.setMaxNotValidBeforeDelta, 1<<15, callflag.States) n.AddMethod(md, desc) return n diff --git a/pkg/core/native/oracle.go b/pkg/core/native/oracle.go index bc2859fc8..5533eaf66 100644 --- a/pkg/core/native/oracle.go +++ b/pkg/core/native/oracle.go @@ -40,6 +40,9 @@ type Oracle struct { Desig *Designate oracleScript []byte + requestPrice atomic.Value + requestPriceChanged atomic.Value + // Module is an oracle module capable of talking with the external world. Module atomic.Value // newRequests contains new requests created during current block. @@ -55,13 +58,15 @@ const ( // maxRequestsCount is the maximum number of requests per URL maxRequestsCount = 256 - oracleRequestPrice = 5000_0000 + // DefaultOracleRequestPrice is default amount GAS needed for oracle request. + DefaultOracleRequestPrice = 5000_0000 ) var ( - prefixIDList = []byte{6} - prefixRequest = []byte{7} - prefixRequestID = []byte{9} + prefixRequestPrice = []byte{5} + prefixIDList = []byte{6} + prefixRequest = []byte{7} + prefixRequestID = []byte{9} ) // Various validation errors. @@ -91,7 +96,7 @@ func newOracle() *Oracle { manifest.NewParameter("callback", smartcontract.StringType), manifest.NewParameter("userData", smartcontract.AnyType), manifest.NewParameter("gasForResponse", smartcontract.IntegerType)) - md := newMethodAndPrice(o.request, oracleRequestPrice, callflag.States|callflag.AllowNotify) + md := newMethodAndPrice(o.request, 0, callflag.States|callflag.AllowNotify) o.AddMethod(md, desc) desc = newDescriptor("finish", smartcontract.VoidType) @@ -99,7 +104,7 @@ func newOracle() *Oracle { o.AddMethod(md, desc) desc = newDescriptor("verify", smartcontract.BoolType) - md = newMethodAndPrice(o.verify, 100_0000, callflag.NoneFlag) + md = newMethodAndPrice(o.verify, 1<<15, callflag.NoneFlag) o.AddMethod(md, desc) o.AddEvent("OracleRequest", manifest.NewParameter("Id", smartcontract.IntegerType), @@ -109,6 +114,17 @@ func newOracle() *Oracle { o.AddEvent("OracleResponse", manifest.NewParameter("Id", smartcontract.IntegerType), manifest.NewParameter("OriginalTx", smartcontract.Hash256Type)) + desc = newDescriptor("getPrice", smartcontract.IntegerType) + md = newMethodAndPrice(o.getPrice, 1<<15, callflag.ReadStates) + o.AddMethod(md, desc) + + desc = newDescriptor("setPrice", smartcontract.VoidType, + manifest.NewParameter("price", smartcontract.IntegerType)) + md = newMethodAndPrice(o.setPrice, 1<<15, callflag.States) + o.AddMethod(md, desc) + + o.requestPriceChanged.Store(true) + return o } @@ -130,9 +146,15 @@ func (o *Oracle) OnPersist(ic *interop.Context) error { // PostPersist represents `postPersist` method. func (o *Oracle) PostPersist(ic *interop.Context) error { + p := o.getPriceInternal(ic.DAO) + if o.requestPriceChanged.Load().(bool) { + o.requestPrice.Store(p) + o.requestPriceChanged.Store(false) + } + var nodes keys.PublicKeys var reward []big.Int - single := new(big.Int).SetUint64(oracleRequestPrice) + single := big.NewInt(p) var removedIDs []uint64 orc, _ := o.Module.Load().(services.Oracle) @@ -202,7 +224,15 @@ func (o *Oracle) Metadata() *interop.ContractMD { // Initialize initializes Oracle contract. func (o *Oracle) Initialize(ic *interop.Context) error { - return setIntWithKey(o.ID, ic.DAO, prefixRequestID, 0) + if err := setIntWithKey(o.ID, ic.DAO, prefixRequestID, 0); err != nil { + return err + } + if err := setIntWithKey(o.ID, ic.DAO, prefixRequestPrice, DefaultOracleRequestPrice); err != nil { + return err + } + o.requestPrice.Store(int64(DefaultOracleRequestPrice)) + o.requestPriceChanged.Store(false) + return nil } func getResponse(tx *transaction.Transaction) *transaction.OracleResponse { @@ -281,6 +311,9 @@ 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) } @@ -404,6 +437,32 @@ func (o *Oracle) verify(ic *interop.Context, _ []stackitem.Item) stackitem.Item return stackitem.NewBool(ic.Tx.HasAttribute(transaction.OracleResponseT)) } +func (o *Oracle) getPrice(ic *interop.Context, _ []stackitem.Item) stackitem.Item { + return stackitem.NewBigInteger(big.NewInt(o.getPriceInternal(ic.DAO))) +} + +func (o *Oracle) getPriceInternal(d dao.DAO) int64 { + if !o.requestPriceChanged.Load().(bool) { + return o.requestPrice.Load().(int64) + } + return getIntWithKey(o.ID, d, prefixRequestPrice) +} + +func (o *Oracle) setPrice(ic *interop.Context, args []stackitem.Item) stackitem.Item { + price := toBigInt(args[0]) + if price.Sign() <= 0 || !price.IsInt64() { + panic("invalid register price") + } + if !o.NEO.checkCommittee(ic) { + panic("invalid committee signature") + } + if err := setIntWithKey(o.ID, ic.DAO, prefixRequestPrice, price.Int64()); err != nil { + panic(err) + } + o.requestPriceChanged.Store(true) + return stackitem.Null{} +} + func (o *Oracle) getOriginalTxID(d dao.DAO, tx *transaction.Transaction) util.Uint256 { for i := range tx.Attributes { if tx.Attributes[i].Type == transaction.OracleResponseT { diff --git a/pkg/core/native/policy.go b/pkg/core/native/policy.go index 882ccc935..8c063bca7 100644 --- a/pkg/core/native/policy.go +++ b/pkg/core/native/policy.go @@ -72,45 +72,45 @@ func newPolicy() *Policy { defer p.UpdateHash() desc := newDescriptor("getFeePerByte", smartcontract.IntegerType) - md := newMethodAndPrice(p.getFeePerByte, 1000000, callflag.ReadStates) + md := newMethodAndPrice(p.getFeePerByte, 1<<15, callflag.ReadStates) p.AddMethod(md, desc) desc = newDescriptor("isBlocked", smartcontract.BoolType, manifest.NewParameter("account", smartcontract.Hash160Type)) - md = newMethodAndPrice(p.isBlocked, 1000000, callflag.ReadStates) + md = newMethodAndPrice(p.isBlocked, 1<<15, callflag.ReadStates) p.AddMethod(md, desc) desc = newDescriptor("getExecFeeFactor", smartcontract.IntegerType) - md = newMethodAndPrice(p.getExecFeeFactor, 1000000, callflag.ReadStates) + md = newMethodAndPrice(p.getExecFeeFactor, 1<<15, callflag.ReadStates) p.AddMethod(md, desc) desc = newDescriptor("setExecFeeFactor", smartcontract.VoidType, manifest.NewParameter("value", smartcontract.IntegerType)) - md = newMethodAndPrice(p.setExecFeeFactor, 3000000, callflag.States) + md = newMethodAndPrice(p.setExecFeeFactor, 1<<15, callflag.States) p.AddMethod(md, desc) desc = newDescriptor("getStoragePrice", smartcontract.IntegerType) - md = newMethodAndPrice(p.getStoragePrice, 1000000, callflag.ReadStates) + md = newMethodAndPrice(p.getStoragePrice, 1<<15, callflag.ReadStates) p.AddMethod(md, desc) desc = newDescriptor("setStoragePrice", smartcontract.VoidType, manifest.NewParameter("value", smartcontract.IntegerType)) - md = newMethodAndPrice(p.setStoragePrice, 3000000, callflag.States) + md = newMethodAndPrice(p.setStoragePrice, 1<<15, callflag.States) p.AddMethod(md, desc) desc = newDescriptor("setFeePerByte", smartcontract.VoidType, manifest.NewParameter("value", smartcontract.IntegerType)) - md = newMethodAndPrice(p.setFeePerByte, 3000000, callflag.States) + md = newMethodAndPrice(p.setFeePerByte, 1<<15, callflag.States) p.AddMethod(md, desc) desc = newDescriptor("blockAccount", smartcontract.BoolType, manifest.NewParameter("account", smartcontract.Hash160Type)) - md = newMethodAndPrice(p.blockAccount, 3000000, callflag.States) + md = newMethodAndPrice(p.blockAccount, 1<<15, callflag.States) p.AddMethod(md, desc) desc = newDescriptor("unblockAccount", smartcontract.BoolType, manifest.NewParameter("account", smartcontract.Hash160Type)) - md = newMethodAndPrice(p.unblockAccount, 3000000, callflag.States) + md = newMethodAndPrice(p.unblockAccount, 1<<15, callflag.States) p.AddMethod(md, desc) return p diff --git a/pkg/core/native_contract_test.go b/pkg/core/native_contract_test.go index 8032bfa35..358641c52 100644 --- a/pkg/core/native_contract_test.go +++ b/pkg/core/native_contract_test.go @@ -56,7 +56,10 @@ func (bc *Blockchain) registerNative(c interop.Contract) { bc.contracts.Contracts = append(bc.contracts.Contracts, c) } -const testSumPrice = 1 << 15 * interop.DefaultBaseExecFee // same as contract.Call +const ( + testSumCPUFee = 1 << 15 // same as contract.Call + testSumStorageFee = 200 +) func newTestNative() *testNative { tn := &testNative{ @@ -76,7 +79,8 @@ func newTestNative() *testNative { } md := &interop.MethodAndPrice{ Func: tn.sum, - Price: testSumPrice, + CPUFee: testSumCPUFee, + StorageFee: testSumStorageFee, RequiredFlags: callflag.NoneFlag, } tn.meta.AddMethod(md, desc) @@ -93,7 +97,7 @@ func newTestNative() *testNative { } md = &interop.MethodAndPrice{ Func: tn.callOtherContractNoReturn, - Price: testSumPrice, + CPUFee: testSumCPUFee, RequiredFlags: callflag.NoneFlag} tn.meta.AddMethod(md, desc) @@ -108,7 +112,7 @@ func newTestNative() *testNative { } md = &interop.MethodAndPrice{ Func: tn.callOtherContractWithReturn, - Price: testSumPrice, + CPUFee: testSumCPUFee, RequiredFlags: callflag.NoneFlag} tn.meta.AddMethod(md, desc) @@ -182,7 +186,8 @@ func TestNativeContract_Invoke(t *testing.T) { require.NoError(t, err) // System.Contract.Call + "sum" itself + opcodes for pushing arguments. - price := int64(testSumPrice * 2) + price := int64(testSumCPUFee * chain.GetBaseExecFee() * 2) + price += testSumStorageFee * chain.GetStoragePrice() price += 3 * fee.Opcode(chain.GetBaseExecFee(), opcode.PUSHINT8) price += 2 * fee.Opcode(chain.GetBaseExecFee(), opcode.SYSCALL, opcode.PUSHDATA1, opcode.PUSHINT8) price += fee.Opcode(chain.GetBaseExecFee(), opcode.PACK) @@ -281,15 +286,16 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) { cs, _ := getTestContractState(chain) require.NoError(t, chain.contracts.Management.PutContractState(chain.dao, cs)) + baseFee := chain.GetBaseExecFee() t.Run("non-native, no return", func(t *testing.T) { - res, err := invokeContractMethod(chain, testSumPrice*4+10000, tn.Metadata().Hash, "callOtherContractNoReturn", cs.Hash, "justReturn", []interface{}{}) + res, err := invokeContractMethod(chain, testSumCPUFee*baseFee*4+10000, tn.Metadata().Hash, "callOtherContractNoReturn", cs.Hash, "justReturn", []interface{}{}) require.NoError(t, err) drainTN(t) require.Equal(t, vm.HaltState, res.VMState, res.FaultException) checkResult(t, res, stackitem.Null{}) // simple call is done with EnsureNotEmpty }) t.Run("non-native, with return", func(t *testing.T) { - res, err := invokeContractMethod(chain, testSumPrice*4+10000, tn.Metadata().Hash, + res, err := invokeContractMethod(chain, testSumCPUFee*baseFee*4+10000, tn.Metadata().Hash, "callOtherContractWithReturn", cs.Hash, "ret7", []interface{}{}) require.NoError(t, err) drainTN(t) diff --git a/pkg/core/native_neo_test.go b/pkg/core/native_neo_test.go index 02508d471..d86cd9e47 100644 --- a/pkg/core/native_neo_test.go +++ b/pkg/core/native_neo_test.go @@ -1,6 +1,7 @@ package core import ( + "math" "math/big" "sort" "testing" @@ -290,3 +291,9 @@ func TestNEO_TransferOnPayment(t *testing.T) { require.Equal(t, neoOwner.BytesBE(), arr[1].Value()) require.Equal(t, big.NewInt(amount), arr[2].Value()) } + +func TestRegisterPrice(t *testing.T) { + bc := newTestChain(t) + testGetSet(t, bc, bc.contracts.NEO.Hash, "RegisterPrice", + native.DefaultRegisterPrice, 1, math.MaxInt64) +} diff --git a/pkg/core/native_oracle_test.go b/pkg/core/native_oracle_test.go index 2f692f705..12591014c 100644 --- a/pkg/core/native_oracle_test.go +++ b/pkg/core/native_oracle_test.go @@ -2,6 +2,7 @@ package core import ( "errors" + "math" "math/big" "testing" @@ -248,3 +249,9 @@ func TestOracle_Request(t *testing.T) { }) }) } + +func TestGetSetPrice(t *testing.T) { + bc := newTestChain(t) + testGetSet(t, bc, bc.contracts.Oracle.Hash, "Price", + native.DefaultOracleRequestPrice, 1, math.MaxInt64) +} diff --git a/pkg/core/native_policy_test.go b/pkg/core/native_policy_test.go index 3ca724006..3b315b28c 100644 --- a/pkg/core/native_policy_test.go +++ b/pkg/core/native_policy_test.go @@ -1,6 +1,7 @@ package core import ( + "math/big" "testing" "github.com/nspcc-dev/neo-go/internal/random" @@ -46,7 +47,10 @@ func testGetSet(t *testing.T, chain *Blockchain, hash util.Uint160, name string, if maxValue != 0 { t.Run("set, too large value", func(t *testing.T) { - res, err := invokeContractMethodGeneric(chain, 100000000, hash, setName, true, maxValue+1) + // use big.Int because max can be `math.MaxInt64` + max := big.NewInt(maxValue) + max.Add(max, big.NewInt(1)) + res, err := invokeContractMethodGeneric(chain, 100000000, hash, setName, true, max) require.NoError(t, err) checkFAULTState(t, res) }) diff --git a/pkg/core/oracle_test.go b/pkg/core/oracle_test.go index 332a5a338..2ebda6109 100644 --- a/pkg/core/oracle_test.go +++ b/pkg/core/oracle_test.go @@ -98,8 +98,8 @@ func TestCreateResponseTx(t *testing.T) { tx, err := orc.CreateResponseTx(int64(req.GasForResponse), 1, resp) require.NoError(t, err) assert.Equal(t, 166, tx.Size()) - assert.Equal(t, int64(2215610), tx.NetworkFee) - assert.Equal(t, int64(97784390), tx.SystemFee) + assert.Equal(t, int64(2198650), tx.NetworkFee) + assert.Equal(t, int64(97801350), tx.SystemFee) } func TestOracle_InvalidWallet(t *testing.T) { diff --git a/pkg/interop/native/neo/neo.go b/pkg/interop/native/neo/neo.go index 98c94a223..8144986f3 100644 --- a/pkg/interop/native/neo/neo.go +++ b/pkg/interop/native/neo/neo.go @@ -59,6 +59,16 @@ func SetGASPerBlock(amount int) { contract.Call(interop.Hash160(Hash), "setGasPerBlock", contract.States, amount) } +// GetRegisterPrice represents `getRegisterPrice` method of NEO native contract. +func GetRegisterPrice() int { + return contract.Call(interop.Hash160(Hash), "getRegisterPrice", contract.ReadStates).(int) +} + +// SetRegisterPrice represents `setRegisterPrice` method of NEO native contract. +func SetRegisterPrice(amount int) { + contract.Call(interop.Hash160(Hash), "setRegisterPrice", contract.States, amount) +} + // RegisterCandidate represents `registerCandidate` method of NEO native contract. func RegisterCandidate(pub interop.PublicKey) bool { return contract.Call(interop.Hash160(Hash), "registerCandidate", contract.States, pub).(bool) diff --git a/pkg/interop/native/oracle/oracle.go b/pkg/interop/native/oracle/oracle.go index 06a8f438c..edb6534de 100644 --- a/pkg/interop/native/oracle/oracle.go +++ b/pkg/interop/native/oracle/oracle.go @@ -14,3 +14,13 @@ func Request(url string, filter []byte, cb string, userData interface{}, gasForR contract.States|contract.AllowNotify, url, filter, cb, userData, gasForResponse) } + +// GetPrice represents `getPrice` method of Oracle native contract. +func GetPrice() int { + return contract.Call(interop.Hash160(Hash), "getPrice", contract.ReadStates).(int) +} + +// SetPrice represents `setPrice` method of Oracle native contract. +func SetPrice(amount int) { + contract.Call(interop.Hash160(Hash), "setPrice", contract.States, amount) +} diff --git a/pkg/rpc/client/rpc.go b/pkg/rpc/client/rpc.go index 1706cda70..1308d9848 100644 --- a/pkg/rpc/client/rpc.go +++ b/pkg/rpc/client/rpc.go @@ -694,7 +694,7 @@ func (c *Client) CalculateNotaryFee(nKeys uint8) (int64, error) { fee.Opcode(baseExecFee, // Notary node witness opcode.PUSHDATA1, opcode.RET, // invocation script opcode.PUSH0, opcode.SYSCALL, opcode.RET) + // System.Contract.CallNative - native.NotaryVerificationPrice + // Notary witness verification price + native.NotaryVerificationPrice*baseExecFee + // Notary witness verification price feePerByte*int64(io.GetVarSize(make([]byte, 66))) + // invocation script per-byte fee feePerByte*int64(io.GetVarSize([]byte{})), // verification script per-byte fee nil diff --git a/pkg/vm/emit/emit.go b/pkg/vm/emit/emit.go index 31ea60697..00f7c1b44 100644 --- a/pkg/vm/emit/emit.go +++ b/pkg/vm/emit/emit.go @@ -59,14 +59,21 @@ func Int(w *io.BinWriter, i int64) { val := opcode.Opcode(int(opcode.PUSH1) - 1 + int(i)) Opcodes(w, val) default: - buf := bigint.ToPreallocatedBytes(big.NewInt(i), make([]byte, 0, 32)) - // l != 0 becase of switch - padSize := byte(8 - bits.LeadingZeros8(byte(len(buf)-1))) - Opcodes(w, opcode.PUSHINT8+opcode.Opcode(padSize)) - w.WriteBytes(padRight(1<= 0; i-- { @@ -75,6 +82,8 @@ func Array(w *io.BinWriter, es ...interface{}) { Array(w, e...) case int64: Int(w, e) + case *big.Int: + bigInt(w, e) case string: String(w, e) case util.Uint160: diff --git a/pkg/vm/emit/emit_test.go b/pkg/vm/emit/emit_test.go index 7d1fd9aa2..ea5c996a1 100644 --- a/pkg/vm/emit/emit_test.go +++ b/pkg/vm/emit/emit_test.go @@ -3,6 +3,8 @@ package emit import ( "encoding/binary" "errors" + "math" + "math/big" "testing" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" @@ -144,7 +146,10 @@ func TestBytes(t *testing.T) { func TestEmitArray(t *testing.T) { t.Run("good", func(t *testing.T) { buf := io.NewBufBinWriter() - Array(buf.BinWriter, []interface{}{int64(1), int64(2)}, nil, int64(1), "str", true, []byte{0xCA, 0xFE}) + veryBig := new(big.Int).SetUint64(math.MaxUint64) + veryBig.Add(veryBig, big.NewInt(1)) + Array(buf.BinWriter, big.NewInt(0), veryBig, + []interface{}{int64(1), int64(2)}, nil, int64(1), "str", true, []byte{0xCA, 0xFE}) require.NoError(t, buf.Err) res := buf.Bytes() @@ -163,6 +168,9 @@ func TestEmitArray(t *testing.T) { assert.EqualValues(t, opcode.PUSH1, res[15]) assert.EqualValues(t, opcode.PUSH2, res[16]) assert.EqualValues(t, opcode.PACK, res[17]) + assert.EqualValues(t, opcode.PUSHINT128, res[18]) + assert.EqualValues(t, veryBig, bigint.FromBytes(res[19:35])) + assert.EqualValues(t, opcode.PUSH0, res[35]) }) t.Run("empty", func(t *testing.T) {