From f9f1fe03b2fae3e9f7d58248b988273ae4b08a01 Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Mon, 15 Feb 2021 16:40:44 +0300 Subject: [PATCH 1/2] core: refactor native call 1. `System.Contract.CallNative` expects version on stack. 2. Actual method is determined based on current instruction pointer. 3. Native hashes don't longer depend on NEF checksum. --- cli/testdata/chain50x2.acc | Bin 45879 -> 45879 bytes pkg/core/blockchain.go | 12 +-- pkg/core/blockchain_test.go | 8 +- pkg/core/interop/context.go | 82 +++++++++++++----- pkg/core/interop/contract/call.go | 17 +--- pkg/core/native/compatibility_test.go | 4 +- pkg/core/native/designate.go | 1 + pkg/core/native/interop.go | 21 +++-- pkg/core/native/ledger.go | 2 + pkg/core/native/management.go | 1 + pkg/core/native/name_service.go | 1 + pkg/core/native/native_gas.go | 2 + pkg/core/native/native_neo.go | 2 + pkg/core/native/notary.go | 1 + pkg/core/native/oracle.go | 1 + pkg/core/native/policy.go | 1 + pkg/core/native_contract_test.go | 29 ++++--- pkg/core/oracle_test.go | 3 + pkg/core/state/contract.go | 12 --- pkg/interop/native/gas/gas.go | 2 +- pkg/interop/native/ledger/ledger.go | 2 +- pkg/interop/native/management/management.go | 2 +- .../native/nameservice/name_service.go | 2 +- pkg/interop/native/neo/neo.go | 2 +- pkg/interop/native/notary/notary.go | 2 +- pkg/interop/native/oracle/oracle.go | 2 +- pkg/interop/native/policy/policy.go | 2 +- pkg/interop/native/roles/roles.go | 2 +- pkg/rpc/client/rpc.go | 2 +- pkg/rpc/server/server_test.go | 4 +- pkg/rpc/server/testdata/testblocks.acc | Bin 9869 -> 9869 bytes pkg/services/oracle/oracle.go | 1 + pkg/services/oracle/response.go | 5 +- 33 files changed, 128 insertions(+), 102 deletions(-) diff --git a/cli/testdata/chain50x2.acc b/cli/testdata/chain50x2.acc index 93a3cc46f6b39753dc888d2e459c615100014096..1c8067f4eb77159e46b3465c5ae8e904376d547b 100644 GIT binary patch literal 45879 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 literal 45879 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 diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 768c91367..7a59940b1 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1753,7 +1753,6 @@ var ( // initVerificationVM initializes VM for witness check. func (bc *Blockchain) initVerificationVM(ic *interop.Context, hash util.Uint160, witness *transaction.Witness) error { - isNative := false v := ic.VM if len(witness.VerificationScript) != 0 { if witness.ScriptHash() != hash { @@ -1781,8 +1780,7 @@ func (bc *Blockchain) initVerificationVM(ic *interop.Context, hash util.Uint160, v.Context().NEF = &cs.NEF v.Jump(v.Context(), md.Offset) - isNative = cs.ID <= 0 - if !isNative && initMD != nil { + if initMD != nil { v.Call(v.Context(), initMD.Offset) } } @@ -1792,14 +1790,6 @@ func (bc *Blockchain) initVerificationVM(ic *interop.Context, hash util.Uint160, return fmt.Errorf("%w: %v", ErrInvalidInvocation, err) } v.LoadScript(witness.InvocationScript) - if isNative { - if err := v.StepOut(); err != nil { - return err - } - } - } - if isNative { - v.Estack().PushVal(manifest.MethodVerify) } return nil } diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 5faf3a9d6..7380bfc66 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -25,6 +25,7 @@ import ( "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/keys" + "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" @@ -591,7 +592,7 @@ func TestVerifyTx(t *testing.T) { w := io.NewBufBinWriter() emit.Opcodes(w.BinWriter, opcode.ABORT) emit.Bytes(w.BinWriter, util.Uint160{}.BytesBE()) - emit.Int(w.BinWriter, int64(orc.NEF.Checksum)) + emit.Int(w.BinWriter, 0) emit.String(w.BinWriter, orc.Manifest.Name) tx.Scripts[len(tx.Scripts)-1].VerificationScript = w.Bytes() err := bc.VerifyTx(tx) @@ -1005,7 +1006,7 @@ func TestVerifyTx(t *testing.T) { transaction.NotaryServiceFeePerKey + // fee for Notary attribute fee.Opcode(bc.GetBaseExecFee(), // Notary verification script opcode.PUSHDATA1, opcode.RET, // invocation script - opcode.PUSHINT8, opcode.SYSCALL, opcode.RET) + // Neo.Native.Call + opcode.PUSH0, opcode.SYSCALL, opcode.RET) + // Neo.Native.Call native.NotaryVerificationPrice // Notary witness verification price tx.Scripts = []transaction.Witness{ { @@ -1204,7 +1205,8 @@ func TestIsTxStillRelevant(t *testing.T) { "github.com/nspcc-dev/neo-go/pkg/interop/util" ) func Verify() bool { - currentHeight := contract.Call(util.FromAddress("NV5WuMGkwhQexQ4afTwuRojMeWwfWrEAdv"), "currentIndex", contract.ReadStates) + addr := util.FromAddress("`+address.Uint160ToString(bc.contracts.Ledger.Hash)+`") + currentHeight := contract.Call(addr, "currentIndex", contract.ReadStates) return currentHeight.(int) < %d }`, bc.BlockHeight()+2) // deploy + next block txDeploy, h, err := testchain.NewDeployTx(bc, "TestVerify", neoOwner, strings.NewReader(src)) diff --git a/pkg/core/interop/context.go b/pkg/core/interop/context.go index 8ce2cf65b..121cf23d5 100644 --- a/pkg/core/interop/context.go +++ b/pkg/core/interop/context.go @@ -4,19 +4,24 @@ import ( "errors" "fmt" "sort" + "strings" "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/blockchainer" "github.com/nspcc-dev/neo-go/pkg/core/dao" + "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "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/crypto" + "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "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/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "go.uber.org/zap" ) @@ -86,6 +91,7 @@ type MethodAndPrice struct { Func Method MD *manifest.Method Price int64 + SyscallOffset int RequiredFlags callflag.CallFlag } @@ -101,21 +107,12 @@ type Contract interface { type ContractMD struct { state.NativeContract Name string - Methods map[MethodAndArgCount]MethodAndPrice -} - -// MethodAndArgCount represents method's signature. -type MethodAndArgCount struct { - Name string - ArgCount int + Methods []MethodAndPrice } // NewContractMD returns Contract with the specified list of methods. func NewContractMD(name string, id int32) *ContractMD { - c := &ContractMD{ - Name: name, - Methods: make(map[MethodAndArgCount]MethodAndPrice), - } + c := &ContractMD{Name: name} c.ID = id @@ -123,14 +120,32 @@ func NewContractMD(name string, id int32) *ContractMD { // Therefore values are taken from C# node. c.NEF.Header.Compiler = "neo-core-v3.0" c.NEF.Header.Magic = nef.Magic - c.NEF.Script = state.CreateNativeContractScript(id) - c.NEF.Checksum = c.NEF.CalculateChecksum() - c.Hash = state.CreateContractHash(util.Uint160{}, c.NEF.Checksum, name) + c.Hash = state.CreateContractHash(util.Uint160{}, 0, c.Name) c.Manifest = *manifest.DefaultManifest(name) return c } +// UpdateHash creates native contract script and updates hash. +func (c *ContractMD) UpdateHash() { + w := io.NewBufBinWriter() + for i := range c.Methods { + offset := w.Len() + c.Methods[i].MD.Offset = offset + c.Manifest.ABI.Methods[i].Offset = offset + emit.Int(w.BinWriter, 0) + c.Methods[i].SyscallOffset = w.Len() + emit.Syscall(w.BinWriter, interopnames.SystemContractCallNative) + emit.Opcodes(w.BinWriter, opcode.RET) + } + if w.Err != nil { + panic(fmt.Errorf("can't create native contract script: %w", w.Err)) + } + + c.NEF.Script = w.Bytes() + c.NEF.Checksum = c.NEF.CalculateChecksum() +} + // AddMethod adds new method to a native contract. func (c *ContractMD) AddMethod(md *MethodAndPrice, desc *manifest.Method) { md.MD = desc @@ -147,21 +162,42 @@ func (c *ContractMD) AddMethod(md *MethodAndPrice, desc *manifest.Method) { copy(c.Manifest.ABI.Methods[index+1:], c.Manifest.ABI.Methods[index:]) c.Manifest.ABI.Methods[index] = *desc - key := MethodAndArgCount{ - Name: desc.Name, - ArgCount: len(desc.Parameters), + // Cache follows the same order. + c.Methods = append(c.Methods, MethodAndPrice{}) + copy(c.Methods[index+1:], c.Methods[index:]) + c.Methods[index] = *md +} + +// GetMethodByOffset returns with the provided offset. +// Offset is offset of `System.Contract.CallNative` syscall. +func (c *ContractMD) GetMethodByOffset(offset int) (MethodAndPrice, bool) { + for k := range c.Methods { + if c.Methods[k].SyscallOffset == offset { + return c.Methods[k], true + } } - c.Methods[key] = *md + return MethodAndPrice{}, false } // GetMethod returns method `name` with specified number of parameters. func (c *ContractMD) GetMethod(name string, paramCount int) (MethodAndPrice, bool) { - key := MethodAndArgCount{ - Name: name, - ArgCount: paramCount, + index := sort.Search(len(c.Methods), func(i int) bool { + md := c.Methods[i] + res := strings.Compare(name, md.MD.Name) + switch res { + case -1, 1: + return res == -1 + default: + return paramCount <= len(md.MD.Parameters) + } + }) + if index < len(c.Methods) { + md := c.Methods[index] + if md.MD.Name == name && (paramCount == -1 || len(md.MD.Parameters) == paramCount) { + return md, true + } } - mp, ok := c.Methods[key] - return mp, ok + return MethodAndPrice{}, false } // AddEvent adds new event to a native contract. diff --git a/pkg/core/interop/contract/call.go b/pkg/core/interop/contract/call.go index c84dcfc64..2bb689138 100644 --- a/pkg/core/interop/contract/call.go +++ b/pkg/core/interop/contract/call.go @@ -98,24 +98,13 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra } ic.VM.Invocations[cs.Hash]++ - ic.VM.LoadScriptWithCallingHash(caller, cs.NEF.Script, cs.Hash, ic.VM.Context().GetCallFlags()&f, true, uint16(len(args))) + ic.VM.LoadScriptWithCallingHash(caller, cs.NEF.Script, cs.Hash, ic.VM.Context().GetCallFlags()&f, hasReturn, uint16(len(args))) ic.VM.Context().NEF = &cs.NEF - var isNative bool - for i := range ic.Natives { - if ic.Natives[i].Metadata().Hash.Equals(cs.Hash) { - isNative = true - break - } - } for i := len(args) - 1; i >= 0; i-- { ic.VM.Estack().PushVal(args[i]) } - if isNative { - ic.VM.Estack().PushVal(name) - } else { - // use Jump not Call here because context was loaded in LoadScript above. - ic.VM.Jump(ic.VM.Context(), md.Offset) - } + // use Jump not Call here because context was loaded in LoadScript above. + ic.VM.Jump(ic.VM.Context(), md.Offset) if hasReturn { ic.VM.Context().RetCount = 1 } else { diff --git a/pkg/core/native/compatibility_test.go b/pkg/core/native/compatibility_test.go index d055628be..1b8e3c37c 100644 --- a/pkg/core/native/compatibility_test.go +++ b/pkg/core/native/compatibility_test.go @@ -12,8 +12,8 @@ func TestNamesASCII(t *testing.T) { cs := NewContracts(true) for _, c := range cs.Contracts { require.True(t, isASCII(c.Metadata().Name)) - for m := range c.Metadata().Methods { - require.True(t, isASCII(m.Name)) + for _, m := range c.Metadata().Methods { + require.True(t, isASCII(m.MD.Name)) } for _, e := range c.Metadata().Manifest.ABI.Events { require.True(t, isASCII(e.Name)) diff --git a/pkg/core/native/designate.go b/pkg/core/native/designate.go index 3b6dfa391..490376e92 100644 --- a/pkg/core/native/designate.go +++ b/pkg/core/native/designate.go @@ -81,6 +81,7 @@ func (s *Designate) isValidRole(r Role) bool { func newDesignate(p2pSigExtensionsEnabled bool) *Designate { s := &Designate{ContractMD: *interop.NewContractMD(nativenames.Designation, designateContractID)} s.p2pSigExtensionsEnabled = p2pSigExtensionsEnabled + defer s.UpdateHash() desc := newDescriptor("getDesignatedByRole", smartcontract.ArrayType, manifest.NewParameter("role", smartcontract.IntegerType), diff --git a/pkg/core/native/interop.go b/pkg/core/native/interop.go index 340b0d3c9..99853eded 100644 --- a/pkg/core/native/interop.go +++ b/pkg/core/native/interop.go @@ -12,28 +12,27 @@ import ( // Call calls specified native contract method. func Call(ic *interop.Context) error { - id := int32(ic.VM.Estack().Pop().BigInt().Int64()) + version := ic.VM.Estack().Pop().BigInt().Int64() + if version != 0 { + return fmt.Errorf("native contract of version %d is not active", version) + } var c interop.Contract for _, ctr := range ic.Natives { - if ctr.Metadata().ID == id { + if ctr.Metadata().Hash == ic.VM.GetCurrentScriptHash() { c = ctr break } } if c == nil { - return fmt.Errorf("native contract %d not found", id) + return fmt.Errorf("native contract %d not found", version) } - h := ic.VM.GetCurrentScriptHash() - if !h.Equals(c.Metadata().Hash) { - return errors.New("it is not allowed to use Neo.Native.Call directly to call native contracts. System.Contract.Call should be used") - } - operation := ic.VM.Estack().Pop().String() - m, ok := c.Metadata().GetMethod(operation, ic.VM.Estack().Len()) + m, ok := c.Metadata().GetMethodByOffset(ic.VM.Context().IP()) if !ok { - return fmt.Errorf("method %s not found", operation) + return fmt.Errorf("method not found") } if !ic.VM.Context().GetCallFlags().Has(m.RequiredFlags) { - return fmt.Errorf("missing call flags for native %d `%s` operation call: %05b vs %05b", id, operation, ic.VM.Context().GetCallFlags(), m.RequiredFlags) + 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) { diff --git a/pkg/core/native/ledger.go b/pkg/core/native/ledger.go index 15817910d..60ea77594 100644 --- a/pkg/core/native/ledger.go +++ b/pkg/core/native/ledger.go @@ -39,6 +39,8 @@ func newLedger() *Ledger { var l = &Ledger{ ContractMD: *interop.NewContractMD(nativenames.Ledger, ledgerContractID), } + defer l.UpdateHash() + desc := newDescriptor("currentHash", smartcontract.Hash256Type) md := newMethodAndPrice(l.currentHash, 1000000, callflag.ReadStates) l.AddMethod(md, desc) diff --git a/pkg/core/native/management.go b/pkg/core/native/management.go index 2a53f85fd..eb4582df2 100644 --- a/pkg/core/native/management.go +++ b/pkg/core/native/management.go @@ -65,6 +65,7 @@ func newManagement() *Management { ContractMD: *interop.NewContractMD(nativenames.Management, managementContractID), contracts: make(map[util.Uint160]*state.Contract), } + defer m.UpdateHash() desc := newDescriptor("getContract", smartcontract.ArrayType, manifest.NewParameter("hash", smartcontract.Hash160Type)) diff --git a/pkg/core/native/name_service.go b/pkg/core/native/name_service.go index 2a84c7599..ab724eb7c 100644 --- a/pkg/core/native/name_service.go +++ b/pkg/core/native/name_service.go @@ -100,6 +100,7 @@ func newNameService() *NameService { } n := &NameService{nonfungible: *nf} + defer n.UpdateHash() desc := newDescriptor("addRoot", smartcontract.VoidType, manifest.NewParameter("root", smartcontract.StringType)) diff --git a/pkg/core/native/native_gas.go b/pkg/core/native/native_gas.go index 00111cea1..719706eb1 100644 --- a/pkg/core/native/native_gas.go +++ b/pkg/core/native/native_gas.go @@ -27,6 +27,8 @@ const initialGAS = 30000000 // newGAS returns GAS native contract. func newGAS() *GAS { g := &GAS{} + defer g.UpdateHash() + nep17 := newNEP17Native(nativenames.Gas, gasContractID) nep17.symbol = "GAS" nep17.decimals = 8 diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index 546e11094..24ec29dd9 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -94,6 +94,8 @@ func makeValidatorKey(key *keys.PublicKey) []byte { // newNEO returns NEO native contract. func newNEO() *NEO { n := &NEO{} + defer n.UpdateHash() + nep17 := newNEP17Native(nativenames.Neo, neoContractID) nep17.symbol = "NEO" nep17.decimals = 0 diff --git a/pkg/core/native/notary.go b/pkg/core/native/notary.go index a1b7e3f86..8bfeecd68 100644 --- a/pkg/core/native/notary.go +++ b/pkg/core/native/notary.go @@ -54,6 +54,7 @@ var maxNotValidBeforeDeltaKey = []byte{10} // newNotary returns Notary native contract. func newNotary() *Notary { n := &Notary{ContractMD: *interop.NewContractMD(nativenames.Notary, notaryContractID)} + defer n.UpdateHash() desc := newDescriptor("onNEP17Payment", smartcontract.VoidType, manifest.NewParameter("from", smartcontract.Hash160Type), diff --git a/pkg/core/native/oracle.go b/pkg/core/native/oracle.go index 12d1d7da4..cd6fce0ad 100644 --- a/pkg/core/native/oracle.go +++ b/pkg/core/native/oracle.go @@ -75,6 +75,7 @@ var ( func newOracle() *Oracle { o := &Oracle{ContractMD: *interop.NewContractMD(nativenames.Oracle, oracleContractID)} + defer o.UpdateHash() w := io.NewBufBinWriter() emit.Opcodes(w.BinWriter, opcode.NEWARRAY0) diff --git a/pkg/core/native/policy.go b/pkg/core/native/policy.go index 91ed2f521..3b14d693f 100644 --- a/pkg/core/native/policy.go +++ b/pkg/core/native/policy.go @@ -86,6 +86,7 @@ var _ interop.Contract = (*Policy)(nil) // newPolicy returns Policy native contract. func newPolicy() *Policy { p := &Policy{ContractMD: *interop.NewContractMD(nativenames.Policy, policyContractID)} + defer p.UpdateHash() desc := newDescriptor("getMaxTransactionsPerBlock", smartcontract.IntegerType) md := newMethodAndPrice(p.getMaxTransactionsPerBlock, 1000000, callflag.ReadStates) diff --git a/pkg/core/native_contract_test.go b/pkg/core/native_contract_test.go index 5a5e85493..d3df07d33 100644 --- a/pkg/core/native_contract_test.go +++ b/pkg/core/native_contract_test.go @@ -10,7 +10,6 @@ import ( "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/core/interop/contract" - "github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/smartcontract" @@ -64,6 +63,8 @@ func newTestNative() *testNative { meta: *interop.NewContractMD("Test.Native.Sum", 0), blocks: make(chan uint32, 1), } + defer tn.meta.UpdateHash() + desc := &manifest.Method{ Name: "sum", Parameters: []manifest.Parameter{ @@ -222,27 +223,33 @@ func TestNativeContract_InvokeInternal(t *testing.T) { d := dao.NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet, chain.config.StateRootInHeader) ic := chain.newInteropContext(trigger.Application, d, nil, nil) - v := ic.SpawnVM() + + sumOffset := 0 + for _, md := range tn.Metadata().Methods { + if md.MD.Name == "sum" { + sumOffset = md.MD.Offset + break + } + } t.Run("fail, bad current script hash", func(t *testing.T) { - v.LoadScriptWithHash([]byte{1}, util.Uint160{1, 2, 3}, callflag.All) + v := ic.SpawnVM() + v.LoadScriptWithHash(tn.Metadata().NEF.Script, util.Uint160{1, 2, 3}, callflag.All) v.Estack().PushVal(14) v.Estack().PushVal(28) - v.Estack().PushVal("sum") - v.Estack().PushVal(tn.Metadata().Name) + v.Jump(v.Context(), sumOffset) // it's prohibited to call natives directly - require.Error(t, native.Call(ic)) + require.Error(t, v.Run()) }) t.Run("success", func(t *testing.T) { - v.LoadScriptWithHash([]byte{1}, tn.Metadata().Hash, callflag.All) + v := ic.SpawnVM() + v.LoadScriptWithHash(tn.Metadata().NEF.Script, tn.Metadata().Hash, callflag.All) v.Estack().PushVal(14) v.Estack().PushVal(28) - v.Estack().PushVal("sum") - v.Estack().PushVal(tn.Metadata().ID) - - require.NoError(t, native.Call(ic)) + v.Jump(v.Context(), sumOffset) + require.NoError(t, v.Run()) value := v.Estack().Pop().BigInt() require.Equal(t, int64(42), value.Int64()) diff --git a/pkg/core/oracle_test.go b/pkg/core/oracle_test.go index efdf749f1..c767871d6 100644 --- a/pkg/core/oracle_test.go +++ b/pkg/core/oracle_test.go @@ -19,6 +19,7 @@ import ( "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/services/oracle" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/stretchr/testify/assert" @@ -29,6 +30,7 @@ import ( const oracleModulePath = "../services/oracle/" func getOracleConfig(t *testing.T, bc *Blockchain, w, pass string) oracle.Config { + m := bc.contracts.Oracle.Manifest.ABI.GetMethod(manifest.MethodVerify, 0) return oracle.Config{ Log: zaptest.NewLogger(t), Network: netmode.UnitTestNet, @@ -44,6 +46,7 @@ func getOracleConfig(t *testing.T, bc *Blockchain, w, pass string) oracle.Config OracleScript: bc.contracts.Oracle.NEF.Script, OracleResponse: bc.contracts.Oracle.GetOracleResponseScript(), OracleHash: bc.contracts.Oracle.Hash, + VerifyOffset: m.Offset, } } diff --git a/pkg/core/state/contract.go b/pkg/core/state/contract.go index 7e0dd435c..8d918dd90 100644 --- a/pkg/core/state/contract.go +++ b/pkg/core/state/contract.go @@ -5,7 +5,6 @@ import ( "math" "math/big" - "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" @@ -135,14 +134,3 @@ func CreateContractHash(sender util.Uint160, checksum uint32, name string) util. } return hash.Hash160(w.Bytes()) } - -// CreateNativeContractScript returns script for the native contract. -func CreateNativeContractScript(id int32) []byte { - w := io.NewBufBinWriter() - emit.Int(w.BinWriter, int64(id)) - emit.Syscall(w.BinWriter, interopnames.SystemContractCallNative) - if w.Err != nil { - panic(w.Err) - } - return w.Bytes() -} diff --git a/pkg/interop/native/gas/gas.go b/pkg/interop/native/gas/gas.go index 226961c68..e93941429 100644 --- a/pkg/interop/native/gas/gas.go +++ b/pkg/interop/native/gas/gas.go @@ -6,7 +6,7 @@ import ( ) // Hash represents GAS contract hash. -const Hash = "\x28\xb3\xad\xab\x72\x69\xf9\xc2\x18\x1d\xb3\xcb\x74\x1e\xbf\x55\x19\x30\xe2\x70" +const Hash = "\xcf\x76\xe2\x8b\xd0\x06\x2c\x4a\x47\x8e\xe3\x55\x61\x01\x13\x19\xf3\xcf\xa4\xd2" // Symbol represents `symbol` method of GAS native contract. func Symbol() string { diff --git a/pkg/interop/native/ledger/ledger.go b/pkg/interop/native/ledger/ledger.go index fe9787c30..1f3a124ba 100644 --- a/pkg/interop/native/ledger/ledger.go +++ b/pkg/interop/native/ledger/ledger.go @@ -6,7 +6,7 @@ import ( ) // Hash represents Ledger contract hash. -const Hash = "\x64\x87\x5a\x12\xc6\x03\xc6\x1d\xec\xff\xdf\xe7\x88\xce\x10\xdd\xc6\x69\x1d\x97" +const Hash = "\xbe\xf2\x04\x31\x40\x36\x2a\x77\xc1\x50\x99\xc7\xe6\x4c\x12\xf7\x00\xb6\x65\xda" // CurrentHash represents `currentHash` method of Ledger native contract. func CurrentHash() interop.Hash256 { diff --git a/pkg/interop/native/management/management.go b/pkg/interop/native/management/management.go index a68949cb6..d65e9a1fe 100644 --- a/pkg/interop/native/management/management.go +++ b/pkg/interop/native/management/management.go @@ -6,7 +6,7 @@ import ( ) // Hash represents Management contract hash. -const Hash = "\x43\x0e\x9f\x6f\xb3\x13\xa8\xd3\xa2\xb7\x61\x3b\x67\x83\x09\xd1\xd7\xd7\x01\xa5" +const Hash = "\xfd\xa3\xfa\x43\x46\xea\x53\x2a\x25\x8f\xc4\x97\xdd\xad\xdb\x64\x37\xc9\xfd\xff" // Deploy represents `deploy` method of Management native contract. func Deploy(script, manifest []byte) *Contract { diff --git a/pkg/interop/native/nameservice/name_service.go b/pkg/interop/native/nameservice/name_service.go index 5374d040d..ebb24fd26 100644 --- a/pkg/interop/native/nameservice/name_service.go +++ b/pkg/interop/native/nameservice/name_service.go @@ -18,7 +18,7 @@ const ( ) // Hash represents NameService contract hash. -const Hash = "\x8c\x02\xb8\x43\x98\x6b\x3c\x44\x4f\xf8\x6a\xd5\xa9\x43\xfe\x8d\xb6\x24\xb5\xa2" +const Hash = "\x6b\x59\x2b\x87\x66\xcc\x45\x8e\xfa\x7a\x90\x47\x56\x62\xcd\x92\x03\xcf\x8f\x7a" // Symbol represents `symbol` method of NameService native contract. func Symbol() string { diff --git a/pkg/interop/native/neo/neo.go b/pkg/interop/native/neo/neo.go index 731ae088d..98c94a223 100644 --- a/pkg/interop/native/neo/neo.go +++ b/pkg/interop/native/neo/neo.go @@ -6,7 +6,7 @@ import ( ) // Hash represents NEO contract hash. -const Hash = "\x83\xab\x06\x79\xad\x55\xc0\x50\xa1\x3a\xd4\x3f\x59\x36\xea\x73\xf5\xeb\x1e\xf6" +const Hash = "\xf5\x63\xea\x40\xbc\x28\x3d\x4d\x0e\x05\xc4\x8e\xa3\x05\xb3\xf2\xa0\x73\x40\xef" // Symbol represents `symbol` method of NEO native contract. func Symbol() string { diff --git a/pkg/interop/native/notary/notary.go b/pkg/interop/native/notary/notary.go index f94c7159f..ed83dff4d 100644 --- a/pkg/interop/native/notary/notary.go +++ b/pkg/interop/native/notary/notary.go @@ -6,7 +6,7 @@ import ( ) // Hash represents Notary contract hash. -const Hash = "\x0c\xcf\x26\x94\x3f\xb5\xc9\xb6\x05\xe2\x06\xd2\xa2\x75\xbe\x3e\xa6\xa4\x75\xf4" +const Hash = "\x3b\xec\x35\x31\x11\x9b\xba\xd7\x6d\xd0\x44\x92\x0b\x0d\xe6\xc3\x19\x4f\xe1\xc1" // LockDepositUntil represents `lockDepositUntil` method of Notary native contract. func LockDepositUntil(addr interop.Hash160, till int) bool { diff --git a/pkg/interop/native/oracle/oracle.go b/pkg/interop/native/oracle/oracle.go index 356096d6d..06a8f438c 100644 --- a/pkg/interop/native/oracle/oracle.go +++ b/pkg/interop/native/oracle/oracle.go @@ -6,7 +6,7 @@ import ( ) // Hash represents Oracle contract hash. -const Hash = "\xee\x80\x4c\x14\x29\x68\xd4\x78\x8b\x8a\xff\x51\xda\xde\xdf\xcb\x42\xe7\xc0\x8d" +const Hash = "\x58\x87\x17\x11\x7e\x0a\xa8\x10\x72\xaf\xab\x71\xd2\xdd\x89\xfe\x7c\x4b\x92\xfe" // Request represents `request` method of Oracle native contract. func Request(url string, filter []byte, cb string, userData interface{}, gasForResponse int) { diff --git a/pkg/interop/native/policy/policy.go b/pkg/interop/native/policy/policy.go index 63184f70f..0539f23af 100644 --- a/pkg/interop/native/policy/policy.go +++ b/pkg/interop/native/policy/policy.go @@ -6,7 +6,7 @@ import ( ) // Hash represents Policy contract hash. -const Hash = "\xf2\xe2\x08\xed\xcd\x14\x6c\xbe\xe4\x67\x6e\xdf\x79\xb7\x5e\x50\x98\xd3\xbc\x79" +const Hash = "\x7b\xc6\x81\xc0\xa1\xf7\x1d\x54\x34\x57\xb6\x8b\xba\x8d\x5f\x9f\xdd\x4e\x5e\xcc" // GetMaxTransactionsPerBlock represents `getMaxTransactionsPerBlock` method of Policy native contract. func GetMaxTransactionsPerBlock() int { diff --git a/pkg/interop/native/roles/roles.go b/pkg/interop/native/roles/roles.go index daaa564a6..b095466fc 100644 --- a/pkg/interop/native/roles/roles.go +++ b/pkg/interop/native/roles/roles.go @@ -6,7 +6,7 @@ import ( ) // Hash represents RoleManagement contract hash. -const Hash = "\x02\x8b\x00\x50\x70\xb6\x0d\xf1\xc8\xe2\x09\x78\x7b\x49\xce\xbb\x71\x14\x7b\x59" +const Hash = "\xe2\x95\xe3\x91\x54\x4c\x17\x8a\xd9\x4f\x03\xec\x4d\xcd\xff\x78\x53\x4e\xcf\x49" // Role represents node role. type Role byte diff --git a/pkg/rpc/client/rpc.go b/pkg/rpc/client/rpc.go index 78fab452a..c699832b0 100644 --- a/pkg/rpc/client/rpc.go +++ b/pkg/rpc/client/rpc.go @@ -685,7 +685,7 @@ func (c *Client) CalculateNotaryFee(nKeys uint8) (int64, error) { return int64((nKeys+1))*transaction.NotaryServiceFeePerKey + // fee for NotaryAssisted attribute fee.Opcode(baseExecFee, // Notary node witness opcode.PUSHDATA1, opcode.RET, // invocation script - opcode.PUSHINT8, opcode.SYSCALL, opcode.RET) + // System.Contract.CallNative + opcode.PUSH0, opcode.SYSCALL, opcode.RET) + // System.Contract.CallNative native.NotaryVerificationPrice + // 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 diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index fbeebd2a2..c643aa790 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -60,8 +60,8 @@ type rpcTestCase struct { } const testContractHash = "c6436aab21ebd15279b85af8d7b5808d38455b0a" -const deploymentTxHash = "d0de42d5d23211174a50d74fbd4a919631236a63f16431a5a7e7126759e7ba23" -const genesisBlockHash = "0542f4350c6e236d0509bcd98188b0034bfbecc1a0c7fcdb8e4295310d468b70" +const deploymentTxHash = "050e2189d7cd7b719d9c4bbc525d3edcd89ffedb28cc974862d17dda14377612" +const genesisBlockHash = "41d1099030004d60f3b4b7ffe00bf184e84fac3a39ee7136c761e005f0186d93" const verifyContractHash = "03ffc0897543b9b709e0f8cab4a7682dae0ba943" const verifyContractAVM = "570300412d51083021700c14aa8acf859d4fe402b34e673f2156821796a488ebdb30716813cedb2869db289740" diff --git a/pkg/rpc/server/testdata/testblocks.acc b/pkg/rpc/server/testdata/testblocks.acc index 48120fe7473a007b56c50c5eb4087d31ad17bf41..b7bdeaecce5a51549f4d8c9e71c717ad1308b6e3 100644 GIT binary patch delta 3892 zcmcJSm~AOQxT%N!2UpcGB-{aihR)va$Nr@KtZC{CjXMUgn76(Z`kI6ISC2#;mPi?X2Y$O zPmV)@R$aYE7GME-oM72hBFzAz$PP3|H)M#V!GK`134K~lHE&g>oQv`+{ck8o1l*1X zvj8UP-ZXJ;ey9}he@=4Lg-EJYGJhF;L0KjgVwtLqxNGCajN*yWfeVP&f?$3NOg|70 zuW7O@yFCl2U2&wtC3s@u#Qd37FEkyV`*#rF`D1^u1#)FE^;Wy<3PHXccedm!e?4T(2u!Xw+t9c+ z#HS$Hh6;Qr#lr6vknP|hU9qxnKoYA1f*qJ|XMG0{ub4j=mUoZBb5*l-Rn1LH z^qUy2r4unm9dXWko$bNh7>s6IC!?KjH9l(Ch+Nmcam=Q-#(Jfreu@3Ry&Kq{c2 zidr_b1<+qV?9UncKdtiwH@%=DoWyMEUv*ULWMtm4&tP%x_vCFNc|~47oLPHn75VE< zua!QU9Iv%9F`!I43RRRMRrUb%r?6`XZs0&L8U&55y{TL4<{F*8!^`fRw+RfYWL(2G zxZqwH(L=R|Epw7a?>JRlnp#u^DCH({L2|JT23#|CB9M};o zyRd{}PC1uDN0b|otR%)qeS3T>!Mojs{!^jIP1(Zv0V@63TiDzacF z1#0>~S|5ay6I>m%3-cbyf-O$cV@F!1NM}84pK{@Mb;Y3#f+W%zTR?`X1!QM5=~(nGuG1T%9J^Dz^0XOl55w$trAp6z8 z$}di&#s=Rjl?1_v(>eLqf(NKWkE&U)Kj?odN7m;48g)tB$e5P*Mui%amQbbbqWFvE z=?=Zh+6}wiUO%Q^(1K%7{oRt3lrPsW{mDYVAhSl_0~(?|$xX1yKvw{|i97^7K^BX4 zWA(!ZQ3?`TUSyvt-`~{d<9^$gJX<_%FV%JN`>H8`dmz~2fn}8@Y^oTU{y~#5zCsmc z1a178=c%y8fyU&&a2MGVI2SsNWc^A)s|ipsOS(HTzIFat{S@9Dkg|#dcB!EU+4y+# z2>;GVC*8?Tk#L#gVfAZ>=bkcpZB6Lt5+JYKNtbZ80LzAEQR%hHzZx^-$WY3mF8R7+E@Hsq9;$=d89V&;p6vBj7n7v z#V7RQ5B?Nn9Wsp9L?XuaTo}W-dmNsk;Nh!4upqq|!A*b)DVZ zdCJ$|k1c$(P^3)|r-th@T1KPXGlPX1p|R}1R$~VDWAjh}nr=SZcblC_^NPebON4w{ zQOi|)yLy9*hZ6Ve4}vZhQa}5?v9<@nW)uzSc*8gI!1?;5MR$z~BJ1zZPerz*^Mp?j zau8tVy4T{9vS#M0Ay3H}W+-^JolD0Y%H8Rn{%CW@7{j|B_k&>kzQcvPeGXgDMP<@i zpQVh=Db6u!={l;^j7YV^v`Pk+x!FV;v+`_@CtH>Z;)nNsdX$R3@9pP9R9Uv#FQbdE zZ23&*ZuKunzI1=y9>dqrp4Z&LuK97L_Lo?yQg4WLm3`&vP(q(W{b9_TRTvD7D7Ri= z#)g{~wRvd=%#9-|jWRzxh+YgU9vQr9UpUdqNe9RC)G!(F%vldfRBY&L;(z=Z&mWbM7=VbGcbS98KA?iI)p4 z4EtcGs~Nd6QvL^%*e8tN0MOv@){UOCzb0e^J34$V+xG8BX0dAL^Ihlr5i0P-LhA%= z3WgFJ{V7@i7>fK5i`i%nWKPG4*n}i8)X=UQ7FW7xl6P2=SD4lQOrZOiDb=^lC?iW< z&c-{fQ+6$zBtrWE&kcqn8I8%6c%MNKjN5Bm4ybIEv|%qaV=`j8U!cXS`c!A^H)V%J zxJ{qQ(H+y{jF0Rn@JqLEPE?%V)h7gLZOwY-+4ftQs=vUybuaxhqwE@K$a>wKmM*O> zp0Ws%72sKl!|i~wq?ax(fG*Pi?JVYo}dC+lB;*6ez0N!6l6R1z(74+6{pqn8S_;i$g$WvVzkLDSeH; zJu~&o?c}@nSQC~U)?bTPP-$Ik<3Fv3Zv)%%d<};!1Lf#wM1AwQ7<-)Zfc8E$jqQIZFXe5a zjxzRRIBYc!J?xVIa|5xRkRrgp^M5#XXjW6>F!B%u(ZfEwQ;v= z;nqN5ADlGFo_HWP$bvB4(AnYO1UP>_0e9W&$z#hm_LilWSOT)L)_ZS#s(>iP6&IWQ zV?X(o{UrX=kC{wv*U1z=E>^VrOW}b6<}Qj%FC?-0gI!~=CIKem5pOQjw%?Oyy$2+O zEdwWc5D)wIFI1%7TiSHG+lwF=A)MTMh2=fZAv>;W^;~`$%rPQaml!Ong0}C8y+5<( zFkO+BS5EM$*gsYiZ@&Ohg_+1cbHAt;W4L~)*${X0QPX` zG01+G5TQ-`I_@%{5>H8mZ@sRw*o+o|a$Eh&fV(7P;hyV~Rro;Q1lf%2i1251hT$rr z+{MuwEb9@H-~mAVn3n$V-bIsb=_lX(4hc3^Sy=R}T~aM4fX66OS|NAt4;j&OP;zy_ zfTd{QI&!c`+*>y@-6O8raU@t$wnE9bm#|kECJ$zQ-`y;Yzm1U9S}<)t;aZsyAPSi+ zRKV(Iu*#yhzJitX{@zW%t8A>JhL9O0TW`VE%mNG|oGaVUM6F(#KglY6YSQV@O3yL- z_Dx}xijQDR?$^^=KI7t-Y)?l5i{m-rF8217T}RO%Sb39N@@fZuNCUE9T1N58N^WOk zB>UB#eSQU|iwP=`7?aE>-)Pp-3&ThUSbgGJ<}Q~BP2SuN23+78GvPTcQ6N~Aukhrt z<&8VIBD2s$1J2jRORen>wj7&6-@nDp%iA0MACEE)cIyH|gHP zdQO&H!FKc~8{&!5l4Eo^7ZSOYxEyDo1%5NBL-ZZd_xriNcE9@7JR-dOGXUDgYHmMz z3z4_6;mb(|q;wuWsP}fduIInl@GTA0OXU*D!mwIy9@$`;)^FzF;Af{rfu?h5X^kvN znD36?Rk_@W{&?EqbjrW_95szkq~O1DDu;&H!)$#Nyi@LTR&4~^3CA*zv)kyL_P_rS zZar42|H4I+yII+9EYEZ!Kq!-E6$DEbdKBY!T9BNF9(3@@&`3-zLYP+Hp$V%EtT#OW z-PFPH9<$?lX8rb+Rso?jNiy!1n&J?p=PUG=clUj41ZnDIZ zzB^;(`-^8@q-;%z-yxm9W{b)TmAFprNt|s5^+9k8y#(h6_R22vH!Ibw=75LBKOQH9 zk}Ye#p8=)tr|VnX>wlhz*bNJ}mxSjVe2Zxo%G+L0&QmjY=})q>ctL6C2ZB#2vM(1h z4jdjDtt6ME;xRq6f&rK~$uA+yuO(e3+=yO2T#B%rA{(v1YTVl2+BEltWSgm#K@)=G z3;lk0`9=QGs*RxlT)xq!uC7hdZvBR}sccW??%`4iMZHcV$UP0=2mtAU^_)0#NA&q# z>DgA|GD+4HP%Y`V73uZ7<8gL}lOPVkTLL*3)IS3P07O_3dUo`OUozC^afv9N*?{Y0bLC|0hVH#z(Cd?0e%x{>hJ7A3>4*?`7YBmt9|Q*9(v#rLY&$X84Cy6dE-IesZnEs?jnA7I2rL&Dr=*1i zrCzm`SE-0#)>M(%xuGB-Cowl{43p1HXx(kU@aGNIhujqFNfn3nrJ%wJQ9Q<;QhH-2 z$n^-J6iz^_GlwrBkXneySdk{nnE)vm&Z#z&wSGZ4I6e-{yQBrE0D{wnudJwq!4}V! z9o+?60AEL_7)^9$qx(W9bvM(KBcA1cS(%@)S)~bhz2Vh~R60F*Wuws{8J8WeLEqB2 zD6(MKZ8_z2z!Z6o0CoVXDRj3&EGRh zK-pE$nBOuB_aFy-Q-jz}dRWop1+U5J5*M5^;&5>Q1eeLxnx#BzVIlo2XV4jZCRY&f z1)0@zP#QA5_>Lh=Nwa*m(}+JCg^%5hmOw>frDDyjnsFaJN+Uwm`9+7+&n|Nyp<7VO zYV^|sH`{Ny>SBOs4@g~nGIk+iyw_hJ+iEH-j6UB(N| zld7+$7WCCz3?FIB353-0${WgBhPfPe`_?s9nMH+z;3}*N>+;0a__?HR+9Jg=e?bmp z_|u9f-r-?UCdNv6$0tu8>?X}qZN0-$pp9zP)X?+9J!WbqI0wPLKqG|B=ZmV+dM*J0 zZ;K3ng>mOhAmeU3GdzedKZke$8nhx37-;pa79Z5fA&))D%QKF1tE(`s)!Q6{pS%Zq zL`P;0ednVuZ7F4NG5METzMzlUEu~kSSZy$mR!~{yONVjK`>3lMk{pQETw@!|9*Q+U zVb3(>{uQcdYF3sPH0Rtz3b#Mqk+tqmBA8JO`iwlxY`erWzhlG(_V3_ z{;FmD;|GvLfGKbA>69EA(2nhca8c&{Qw5}#Rd9e-$gIXKywg7lqKkb=n$of}Gq6N8oGF;Za_NrFk~^MSjj%z7LAw;yFcE-;ky{%`tcyi?{=SNC*QOm-@6g~8 zf;Yhw1kb_H2`p{NC=V>vg|GGtScwnE~EE z7LhZZ<{Vf97A}(fKcM-uaG}5M&f=^rgg&3gt4P1vZ*F??{5s?Vy80?KOXa~V|ASxc zc}hMpcNhiNcz)Yp^ovKzrwCG+M~V)VrjpD99cM-$xZU@3b-8^~*rk%pf%B&CNA z+geH0RZQH$9!}M-0DUu%(oP}Qk5W5uZ~vi!{E~{|z#R)E2L+GA3FG^%i|#kK!{atq z7fGu)Bh22m4CXL_>9x)wJu>YBFw)kns~re|x}!ePc5VK;_x`B)hNz1Lp^b}X3!-tj znz_D;!U#KY9SE>K#JpTZ@_c?4kb=e8tw5?Ma%8}rWn0g0O)Ps2Tds)xd@=n6eS^`v z-3X!Q{ssg;apq%X9)q=)j0w(5b`kR#eMqZ3Cy(AM(224~;!HyPZ)AcV@^LgCA-XBW zyzw(OHEOIyx7B(fl*!4>I~l@%CXmp{UJU&A{s(*BfKEk#$iJ>S$KtetP3@Xx~*IAkNp&v_VdPz%Mr*U=FEp#`?|Vwzp0gXS*AsZNsO(4D&6funF^XO_VJRLOXM7$hD#v0NO|xPa$dGTfE$OW$<@IKz9Sh_u0%aj z40X*iNU@dR_B8Je@@NriM?KM#N=yJ7Kjyfmxr>wh)tRW7fOykU41)K_*XW!p98V*6 z3E5Vm8N7uBYlfd%i9~898Sk2PQ)6pLKfSi4{aiVw&jl0}(% z4qg^u&ov|?sGlc6zOt)|bb)Lr$MeJ8{9Ml+ER2iWwaNM=Adt?GPg3@v~EyGPg*W1?$xq7)yJ?MscJetLtI<~>QBChDmAwqox; z&4``lqEH#y@P(=0dlWF0tB*9x7<@KERrJ@Ls+4+h(AL#H7 zp`{v&{HumLpHtG6EJ&wTq0KJ7w6#w9`b}U1e*K$G~};9 zRv^AQMsqT4r8pNpQIHS`9a;?FQWo8@a?-u3P1~^ABt`5z<=c4n!gfeEq{42LT^Vs* zX!m06k6E|;I0AQ)YmVcM8Of`+kfxbAj=67zkJJ@SsP{tVVY-2*Cfg;20iQ|FC+%M~ zRiR{9{aVQosoCNVwBM@#WJB`4xq$&&eglmriUMf4RDriU7bv}bRr=~(8GQ{d&m*FX ze*?Ld-$Z2xx|Ojtl9bH6{I|$xmv6@IC(GUXth+VVkpb1tcG{xEc|S_ICCzw&6u${R z+7%5^PdXAlO^A{LbR0o&-ZKei^~G-5am>P<@;fe{tETEm-IDg6GClozFBO^h-F(;L zel451987F9Kj|Q&KW~CH^p2M3o;N`H_Gu_TS{MWuXL>vy@b&|9l1%Nv>^4%!#Ca-) zQ+k$u)P7wfOF&Yy#*rg0@KYbPn-Ifua5sVDHXzpNgks1oHJrP=iSM{>S0cu`2K0~&|Dhid$wO&u#vKE lLIqgyeQiE^iFTf6(58KyoFBUQtao6N5lhElkG;m@^dBerR<-~D diff --git a/pkg/services/oracle/oracle.go b/pkg/services/oracle/oracle.go index 58e9d4b89..85afffb56 100644 --- a/pkg/services/oracle/oracle.go +++ b/pkg/services/oracle/oracle.go @@ -58,6 +58,7 @@ type ( URIValidator URIValidator OracleScript []byte OracleResponse []byte + VerifyOffset int OracleHash util.Uint160 } diff --git a/pkg/services/oracle/response.go b/pkg/services/oracle/response.go index 3991b0aef..c8d8b2d5c 100644 --- a/pkg/services/oracle/response.go +++ b/pkg/services/oracle/response.go @@ -11,7 +11,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" - "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/vm" "go.uber.org/zap" @@ -137,8 +136,8 @@ func (o *Oracle) CreateResponseTx(gasForResponse int64, height uint32, resp *tra func (o *Oracle) testVerify(tx *transaction.Transaction) (int64, bool) { v := o.Chain.GetTestVM(trigger.Verification, tx, nil) v.GasLimit = o.Chain.GetPolicer().GetMaxVerificationGAS() - v.LoadScriptWithHash(o.OracleScript, o.OracleHash, callflag.ReadStates) - v.Estack().PushVal(manifest.MethodVerify) + v.LoadScriptWithHash(o.OracleScript, o.OracleHash, callflag.ReadOnly) + v.Jump(v.Context(), o.VerifyOffset) ok := isVerifyOk(v) return v.GasConsumed(), ok From 61ce4a7f79eef4c36d89032112ed5cb1aef8b348 Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Mon, 15 Feb 2021 17:06:00 +0300 Subject: [PATCH 2/2] core: set native script and hash in `SetOracle` --- pkg/core/blockchain.go | 9 ++++++++- pkg/core/blockchainer/services/oracle.go | 3 +++ pkg/core/oracle_test.go | 16 +++++++++------- pkg/services/oracle/oracle.go | 22 ++++++++++++++++++---- pkg/services/oracle/response.go | 8 ++++---- 5 files changed, 42 insertions(+), 16 deletions(-) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 7a59940b1..37580f779 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -197,7 +197,14 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.L // SetOracle sets oracle module. It doesn't protected by mutex and // must be called before `bc.Run()` to avoid data race. func (bc *Blockchain) SetOracle(mod services.Oracle) { - bc.contracts.Oracle.Module.Store(mod) + orc := bc.contracts.Oracle + md, ok := orc.GetMethod(manifest.MethodVerify, -1) + if !ok { + panic(fmt.Errorf("%s method not found", manifest.MethodVerify)) + } + mod.UpdateNativeContract(orc.NEF.Script, orc.GetOracleResponseScript(), + orc.Hash, md.MD.Offset) + orc.Module.Store(mod) bc.contracts.Designate.OracleService.Store(mod) } diff --git a/pkg/core/blockchainer/services/oracle.go b/pkg/core/blockchainer/services/oracle.go index 77b534415..102ea390b 100644 --- a/pkg/core/blockchainer/services/oracle.go +++ b/pkg/core/blockchainer/services/oracle.go @@ -3,6 +3,7 @@ package services import ( "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "github.com/nspcc-dev/neo-go/pkg/util" ) // Oracle specifies oracle service interface. @@ -13,6 +14,8 @@ type Oracle interface { RemoveRequests([]uint64) // UpdateOracleNodes updates oracle nodes. UpdateOracleNodes(keys.PublicKeys) + // UpdateNativeContract updates oracle contract native script and hash. + UpdateNativeContract([]byte, []byte, util.Uint160, int) // Run runs oracle module. Must be invoked in a separate goroutine. Run() // Shutdown shutdowns oracle module. diff --git a/pkg/core/oracle_test.go b/pkg/core/oracle_test.go index c767871d6..84e82ff81 100644 --- a/pkg/core/oracle_test.go +++ b/pkg/core/oracle_test.go @@ -30,7 +30,6 @@ import ( const oracleModulePath = "../services/oracle/" func getOracleConfig(t *testing.T, bc *Blockchain, w, pass string) oracle.Config { - m := bc.contracts.Oracle.Manifest.ABI.GetMethod(manifest.MethodVerify, 0) return oracle.Config{ Log: zaptest.NewLogger(t), Network: netmode.UnitTestNet, @@ -41,12 +40,8 @@ func getOracleConfig(t *testing.T, bc *Blockchain, w, pass string) oracle.Config Password: pass, }, }, - Chain: bc, - Client: newDefaultHTTPClient(), - OracleScript: bc.contracts.Oracle.NEF.Script, - OracleResponse: bc.contracts.Oracle.GetOracleResponseScript(), - OracleHash: bc.contracts.Oracle.Hash, - VerifyOffset: m.Offset, + Chain: bc, + Client: newDefaultHTTPClient(), } } @@ -100,6 +95,7 @@ func TestCreateResponseTx(t *testing.T) { } require.NoError(t, bc.contracts.Oracle.PutRequestInternal(1, req, bc.dao)) orc.UpdateOracleNodes(keys.PublicKeys{acc.PrivateKey().PublicKey()}) + bc.SetOracle(orc) tx, err := orc.CreateResponseTx(int64(req.GasForResponse), 1, resp) require.NoError(t, err) assert.Equal(t, 167, tx.Size()) @@ -130,6 +126,12 @@ func TestOracle(t *testing.T) { orc1.UpdateOracleNodes(oracleNodes.Copy()) orc2.UpdateOracleNodes(oracleNodes.Copy()) + orcNative := bc.contracts.Oracle + md, ok := orcNative.GetMethod(manifest.MethodVerify, -1) + require.True(t, ok) + orc1.UpdateNativeContract(orcNative.NEF.Script, orcNative.GetOracleResponseScript(), orcNative.Hash, md.MD.Offset) + orc2.UpdateNativeContract(orcNative.NEF.Script, orcNative.GetOracleResponseScript(), orcNative.Hash, md.MD.Offset) + cs := getOracleContractState(bc.contracts.Oracle.Hash) require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs)) diff --git a/pkg/services/oracle/oracle.go b/pkg/services/oracle/oracle.go index 85afffb56..5a6fe8e2c 100644 --- a/pkg/services/oracle/oracle.go +++ b/pkg/services/oracle/oracle.go @@ -24,6 +24,12 @@ type ( Oracle struct { Config + // This fields are readonly thus not protected by mutex. + oracleHash util.Uint160 + oracleResponse []byte + oracleScript []byte + verifyOffset int + // mtx protects setting callbacks. mtx sync.RWMutex @@ -56,10 +62,6 @@ type ( ResponseHandler Broadcaster OnTransaction TxCallback URIValidator URIValidator - OracleScript []byte - OracleResponse []byte - VerifyOffset int - OracleHash util.Uint160 } // HTTPClient is an interface capable of doing oracle requests. @@ -203,6 +205,18 @@ func (o *Oracle) Run() { } } +// UpdateNativeContract updates native oracle contract info for tx verification. +func (o *Oracle) UpdateNativeContract(script, resp []byte, h util.Uint160, verifyOffset int) { + o.oracleScript = make([]byte, len(script)) + copy(o.oracleScript, script) + + o.oracleResponse = make([]byte, len(resp)) + copy(o.oracleResponse, resp) + + o.oracleHash = h + o.verifyOffset = verifyOffset +} + func (o *Oracle) getOnTransaction() TxCallback { o.mtx.RLock() defer o.mtx.RUnlock() diff --git a/pkg/services/oracle/response.go b/pkg/services/oracle/response.go index c8d8b2d5c..de9a20e38 100644 --- a/pkg/services/oracle/response.go +++ b/pkg/services/oracle/response.go @@ -82,7 +82,7 @@ func readResponse(rc gio.ReadCloser, limit int) ([]byte, error) { // CreateResponseTx creates unsigned oracle response transaction. func (o *Oracle) CreateResponseTx(gasForResponse int64, height uint32, resp *transaction.OracleResponse) (*transaction.Transaction, error) { - tx := transaction.New(o.Network, o.OracleResponse, 0) + tx := transaction.New(o.Network, o.oracleResponse, 0) tx.Nonce = uint32(resp.ID) tx.ValidUntilBlock = height + transaction.MaxValidUntilBlockIncrement tx.Attributes = []transaction.Attribute{{ @@ -93,7 +93,7 @@ func (o *Oracle) CreateResponseTx(gasForResponse int64, height uint32, resp *tra oracleSignContract := o.getOracleSignContract() tx.Signers = []transaction.Signer{ { - Account: o.OracleHash, + Account: o.oracleHash, Scopes: transaction.None, }, { @@ -136,8 +136,8 @@ func (o *Oracle) CreateResponseTx(gasForResponse int64, height uint32, resp *tra func (o *Oracle) testVerify(tx *transaction.Transaction) (int64, bool) { v := o.Chain.GetTestVM(trigger.Verification, tx, nil) v.GasLimit = o.Chain.GetPolicer().GetMaxVerificationGAS() - v.LoadScriptWithHash(o.OracleScript, o.OracleHash, callflag.ReadOnly) - v.Jump(v.Context(), o.VerifyOffset) + v.LoadScriptWithHash(o.oracleScript, o.oracleHash, callflag.ReadOnly) + v.Jump(v.Context(), o.verifyOffset) ok := isVerifyOk(v) return v.GasConsumed(), ok