mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2025-02-19 05:23:36 +00:00
Merge pull request #1229 from nspcc-dev/interop/native_call
core: decouple native contracts from interop service
This commit is contained in:
commit
f24e707ea1
14 changed files with 110 additions and 83 deletions
|
@ -177,8 +177,10 @@ func TestCreateBasicChain(t *testing.T) {
|
||||||
|
|
||||||
gasHash := bc.contracts.GAS.Hash
|
gasHash := bc.contracts.GAS.Hash
|
||||||
neoHash := bc.contracts.NEO.Hash
|
neoHash := bc.contracts.NEO.Hash
|
||||||
|
policyHash := bc.contracts.Policy.Hash
|
||||||
t.Logf("native GAS hash: %v", gasHash)
|
t.Logf("native GAS hash: %v", gasHash)
|
||||||
t.Logf("native NEO hash: %v", neoHash)
|
t.Logf("native NEO hash: %v", neoHash)
|
||||||
|
t.Logf("native Policy hash: %v", policyHash)
|
||||||
|
|
||||||
priv0 := testchain.PrivateKeyByID(0)
|
priv0 := testchain.PrivateKeyByID(0)
|
||||||
priv0ScriptHash := priv0.GetScriptHash()
|
priv0ScriptHash := priv0.GetScriptHash()
|
||||||
|
|
|
@ -83,8 +83,7 @@ type Contract interface {
|
||||||
// ContractMD represents native contract instance.
|
// ContractMD represents native contract instance.
|
||||||
type ContractMD struct {
|
type ContractMD struct {
|
||||||
Manifest manifest.Manifest
|
Manifest manifest.Manifest
|
||||||
ServiceName string
|
Name string
|
||||||
ServiceID uint32
|
|
||||||
ContractID int32
|
ContractID int32
|
||||||
Script []byte
|
Script []byte
|
||||||
Hash util.Uint160
|
Hash util.Uint160
|
||||||
|
@ -94,13 +93,14 @@ type ContractMD struct {
|
||||||
// NewContractMD returns Contract with the specified list of methods.
|
// NewContractMD returns Contract with the specified list of methods.
|
||||||
func NewContractMD(name string) *ContractMD {
|
func NewContractMD(name string) *ContractMD {
|
||||||
c := &ContractMD{
|
c := &ContractMD{
|
||||||
ServiceName: name,
|
Name: name,
|
||||||
ServiceID: emit.InteropNameToID([]byte(name)),
|
|
||||||
Methods: make(map[string]MethodAndPrice),
|
Methods: make(map[string]MethodAndPrice),
|
||||||
}
|
}
|
||||||
|
|
||||||
w := io.NewBufBinWriter()
|
w := io.NewBufBinWriter()
|
||||||
emit.Syscall(w.BinWriter, c.ServiceName)
|
emit.String(w.BinWriter, c.Name)
|
||||||
|
emit.Syscall(w.BinWriter, "Neo.Native.Call")
|
||||||
|
|
||||||
c.Script = w.Bytes()
|
c.Script = w.Bytes()
|
||||||
c.Hash = hash.Hash160(c.Script)
|
c.Hash = hash.Hash160(c.Script)
|
||||||
c.Manifest = *manifest.DefaultManifest(c.Hash)
|
c.Manifest = *manifest.DefaultManifest(c.Hash)
|
||||||
|
|
|
@ -28,9 +28,6 @@ func SpawnVM(ic *interop.Context) *vm.VM {
|
||||||
vm := vm.NewWithTrigger(ic.Trigger)
|
vm := vm.NewWithTrigger(ic.Trigger)
|
||||||
vm.RegisterInteropGetter(getSystemInterop(ic))
|
vm.RegisterInteropGetter(getSystemInterop(ic))
|
||||||
vm.RegisterInteropGetter(getNeoInterop(ic))
|
vm.RegisterInteropGetter(getNeoInterop(ic))
|
||||||
if ic.Chain != nil {
|
|
||||||
vm.RegisterInteropGetter(ic.Chain.(*Blockchain).contracts.GetNativeInterop(ic))
|
|
||||||
}
|
|
||||||
ic.ScriptGetter = vm
|
ic.ScriptGetter = vm
|
||||||
return vm
|
return vm
|
||||||
}
|
}
|
||||||
|
@ -129,6 +126,7 @@ var neoInterops = []interop.Function{
|
||||||
{Name: "Neo.Crypto.CheckMultisigWithECDsaSecp256k1", Func: crypto.ECDSASecp256k1CheckMultisig, Price: 0},
|
{Name: "Neo.Crypto.CheckMultisigWithECDsaSecp256k1", Func: crypto.ECDSASecp256k1CheckMultisig, Price: 0},
|
||||||
{Name: "Neo.Crypto.SHA256", Func: crypto.Sha256, Price: 1000000},
|
{Name: "Neo.Crypto.SHA256", Func: crypto.Sha256, Price: 1000000},
|
||||||
{Name: "Neo.Crypto.RIPEMD160", Func: crypto.RipeMD160, Price: 1000000},
|
{Name: "Neo.Crypto.RIPEMD160", Func: crypto.RipeMD160, Price: 1000000},
|
||||||
|
{Name: "Neo.Native.Call", Func: native.Call, Price: 0},
|
||||||
{Name: "Neo.Native.Deploy", Func: native.Deploy, Price: 0, RequiredFlags: smartcontract.AllowModifyStates},
|
{Name: "Neo.Native.Deploy", Func: native.Deploy, Price: 0, RequiredFlags: smartcontract.AllowModifyStates},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
package native
|
package native
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Contracts is a set of registered native contracts.
|
// Contracts is a set of registered native contracts.
|
||||||
|
@ -32,16 +28,6 @@ func (cs *Contracts) ByHash(h util.Uint160) interop.Contract {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByID returns native contract with the specified id.
|
|
||||||
func (cs *Contracts) ByID(id uint32) interop.Contract {
|
|
||||||
for _, ctr := range cs.Contracts {
|
|
||||||
if ctr.Metadata().ServiceID == id {
|
|
||||||
return ctr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContracts returns new set of native contracts with new GAS, NEO and Policy
|
// NewContracts returns new set of native contracts with new GAS, NEO and Policy
|
||||||
// contracts.
|
// contracts.
|
||||||
func NewContracts() *Contracts {
|
func NewContracts() *Contracts {
|
||||||
|
@ -79,40 +65,3 @@ func (cs *Contracts) GetPersistScript() []byte {
|
||||||
cs.persistScript = w.Bytes()
|
cs.persistScript = w.Bytes()
|
||||||
return cs.persistScript
|
return cs.persistScript
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNativeInterop returns an interop getter for a given set of contracts.
|
|
||||||
func (cs *Contracts) GetNativeInterop(ic *interop.Context) func(uint32) *vm.InteropFuncPrice {
|
|
||||||
return func(id uint32) *vm.InteropFuncPrice {
|
|
||||||
if c := cs.ByID(id); c != nil {
|
|
||||||
return &vm.InteropFuncPrice{
|
|
||||||
Func: getNativeInterop(ic, c),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getNativeInterop returns native contract interop.
|
|
||||||
func getNativeInterop(ic *interop.Context, c interop.Contract) func(v *vm.VM) error {
|
|
||||||
return func(v *vm.VM) error {
|
|
||||||
h := v.GetCurrentScriptHash()
|
|
||||||
if !h.Equals(c.Metadata().Hash) {
|
|
||||||
return errors.New("invalid hash")
|
|
||||||
}
|
|
||||||
name := string(v.Estack().Pop().Bytes())
|
|
||||||
args := v.Estack().Pop().Array()
|
|
||||||
m, ok := c.Metadata().Methods[name]
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("method %s not found", name)
|
|
||||||
}
|
|
||||||
if !v.Context().GetCallFlags().Has(m.RequiredFlags) {
|
|
||||||
return errors.New("missing call flags")
|
|
||||||
}
|
|
||||||
if !v.AddGas(m.Price) {
|
|
||||||
return errors.New("gas limit exceeded")
|
|
||||||
}
|
|
||||||
result := m.Func(ic, args)
|
|
||||||
v.Estack().PushVal(result)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -27,8 +27,42 @@ func Deploy(ic *interop.Context, _ *vm.VM) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := native.Initialize(ic); err != nil {
|
if err := native.Initialize(ic); err != nil {
|
||||||
return fmt.Errorf("initializing %s native contract: %v", md.ServiceName, err)
|
return fmt.Errorf("initializing %s native contract: %v", md.Name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call calls specified native contract method.
|
||||||
|
func Call(ic *interop.Context, v *vm.VM) error {
|
||||||
|
name := string(v.Estack().Pop().Bytes())
|
||||||
|
var c interop.Contract
|
||||||
|
for _, ctr := range ic.Natives {
|
||||||
|
if ctr.Metadata().Name == name {
|
||||||
|
c = ctr
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c == nil {
|
||||||
|
return fmt.Errorf("native contract %s not found", name)
|
||||||
|
}
|
||||||
|
h := v.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 := string(v.Estack().Pop().Bytes())
|
||||||
|
args := v.Estack().Pop().Array()
|
||||||
|
m, ok := c.Metadata().Methods[operation]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("method %s not found", operation)
|
||||||
|
}
|
||||||
|
if !v.Context().GetCallFlags().Has(m.RequiredFlags) {
|
||||||
|
return errors.New("missing call flags")
|
||||||
|
}
|
||||||
|
if !v.AddGas(m.Price) {
|
||||||
|
return errors.New("gas limit exceeded")
|
||||||
|
}
|
||||||
|
result := m.Func(ic, args)
|
||||||
|
v.Estack().PushVal(result)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ type GAS struct {
|
||||||
NEO *NEO
|
NEO *NEO
|
||||||
}
|
}
|
||||||
|
|
||||||
const gasSyscallName = "Neo.Native.Tokens.GAS"
|
const gasName = "GAS"
|
||||||
const gasContractID = -2
|
const gasContractID = -2
|
||||||
|
|
||||||
// GASFactor is a divisor for finding GAS integral value.
|
// GASFactor is a divisor for finding GAS integral value.
|
||||||
|
@ -29,8 +29,7 @@ const initialGAS = 30000000
|
||||||
// NewGAS returns GAS native contract.
|
// NewGAS returns GAS native contract.
|
||||||
func NewGAS() *GAS {
|
func NewGAS() *GAS {
|
||||||
g := &GAS{}
|
g := &GAS{}
|
||||||
nep5 := newNEP5Native(gasSyscallName)
|
nep5 := newNEP5Native(gasName)
|
||||||
nep5.name = "GAS"
|
|
||||||
nep5.symbol = "gas"
|
nep5.symbol = "gas"
|
||||||
nep5.decimals = 8
|
nep5.decimals = 8
|
||||||
nep5.factor = GASFactor
|
nep5.factor = GASFactor
|
||||||
|
|
|
@ -38,7 +38,7 @@ type keyWithVotes struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
neoSyscallName = "Neo.Native.Tokens.NEO"
|
neoName = "NEO"
|
||||||
neoContractID = -1
|
neoContractID = -1
|
||||||
// NEOTotalSupply is the total amount of NEO in the system.
|
// NEOTotalSupply is the total amount of NEO in the system.
|
||||||
NEOTotalSupply = 100000000
|
NEOTotalSupply = 100000000
|
||||||
|
@ -68,8 +68,7 @@ func makeValidatorKey(key *keys.PublicKey) []byte {
|
||||||
// NewNEO returns NEO native contract.
|
// NewNEO returns NEO native contract.
|
||||||
func NewNEO() *NEO {
|
func NewNEO() *NEO {
|
||||||
n := &NEO{}
|
n := &NEO{}
|
||||||
nep5 := newNEP5Native(neoSyscallName)
|
nep5 := newNEP5Native(neoName)
|
||||||
nep5.name = "NEO"
|
|
||||||
nep5.symbol = "neo"
|
nep5.symbol = "neo"
|
||||||
nep5.decimals = 0
|
nep5.decimals = 0
|
||||||
nep5.factor = 1
|
nep5.factor = 1
|
||||||
|
|
|
@ -29,7 +29,6 @@ func makeAccountKey(h util.Uint160) []byte {
|
||||||
// nep5TokenNative represents NEP-5 token contract.
|
// nep5TokenNative represents NEP-5 token contract.
|
||||||
type nep5TokenNative struct {
|
type nep5TokenNative struct {
|
||||||
interop.ContractMD
|
interop.ContractMD
|
||||||
name string
|
|
||||||
symbol string
|
symbol string
|
||||||
decimals int64
|
decimals int64
|
||||||
factor int64
|
factor int64
|
||||||
|
@ -92,7 +91,7 @@ func (c *nep5TokenNative) Initialize(_ *interop.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *nep5TokenNative) Name(_ *interop.Context, _ []stackitem.Item) stackitem.Item {
|
func (c *nep5TokenNative) Name(_ *interop.Context, _ []stackitem.Item) stackitem.Item {
|
||||||
return stackitem.NewByteArray([]byte(c.name))
|
return stackitem.NewByteArray([]byte(c.ContractMD.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *nep5TokenNative) Symbol(_ *interop.Context, _ []stackitem.Item) stackitem.Item {
|
func (c *nep5TokenNative) Symbol(_ *interop.Context, _ []stackitem.Item) stackitem.Item {
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
policySyscallName = "Neo.Native.Policy"
|
policyName = "Policy"
|
||||||
policyContractID = -3
|
policyContractID = -3
|
||||||
|
|
||||||
defaultMaxBlockSize = 1024 * 256
|
defaultMaxBlockSize = 1024 * 256
|
||||||
|
@ -59,7 +59,7 @@ var _ interop.Contract = (*Policy)(nil)
|
||||||
|
|
||||||
// newPolicy returns Policy native contract.
|
// newPolicy returns Policy native contract.
|
||||||
func newPolicy() *Policy {
|
func newPolicy() *Policy {
|
||||||
p := &Policy{ContractMD: *interop.NewContractMD(policySyscallName)}
|
p := &Policy{ContractMD: *interop.NewContractMD(policyName)}
|
||||||
|
|
||||||
p.ContractID = policyContractID
|
p.ContractID = policyContractID
|
||||||
p.Manifest.Features |= smartcontract.HasStorage
|
p.Manifest.Features |= smartcontract.HasStorage
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
|
"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/state"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"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/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"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
@ -140,3 +146,44 @@ func TestNativeContract_Invoke(t *testing.T) {
|
||||||
require.Fail(t, "onPersist wasn't called")
|
require.Fail(t, "onPersist wasn't called")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNativeContract_InvokeInternal(t *testing.T) {
|
||||||
|
chain := newTestChain(t)
|
||||||
|
defer chain.Close()
|
||||||
|
|
||||||
|
tn := newTestNative()
|
||||||
|
chain.registerNative(tn)
|
||||||
|
|
||||||
|
err := chain.dao.PutContractState(&state.Contract{
|
||||||
|
Script: tn.meta.Script,
|
||||||
|
Manifest: tn.meta.Manifest,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
v := vm.New()
|
||||||
|
v.GasLimit = -1
|
||||||
|
ic := chain.newInteropContext(trigger.Application,
|
||||||
|
dao.NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet), nil, nil)
|
||||||
|
|
||||||
|
t.Run("fail, bad current script hash", func(t *testing.T) {
|
||||||
|
v.LoadScriptWithHash([]byte{1}, util.Uint160{1, 2, 3}, smartcontract.All)
|
||||||
|
v.Estack().PushVal(stackitem.NewArray([]stackitem.Item{stackitem.NewBigInteger(big.NewInt(14)), stackitem.NewBigInteger(big.NewInt(28))}))
|
||||||
|
v.Estack().PushVal("sum")
|
||||||
|
v.Estack().PushVal(tn.Metadata().Name)
|
||||||
|
|
||||||
|
// it's prohibited to call natives directly
|
||||||
|
require.Error(t, native.Call(ic, v))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
v.LoadScriptWithHash([]byte{1}, tn.Metadata().Hash, smartcontract.All)
|
||||||
|
v.Estack().PushVal(stackitem.NewArray([]stackitem.Item{stackitem.NewBigInteger(big.NewInt(14)), stackitem.NewBigInteger(big.NewInt(28))}))
|
||||||
|
v.Estack().PushVal("sum")
|
||||||
|
v.Estack().PushVal(tn.Metadata().Name)
|
||||||
|
|
||||||
|
require.NoError(t, native.Call(ic, v))
|
||||||
|
|
||||||
|
value := v.Estack().Pop().BigInt()
|
||||||
|
require.Equal(t, int64(42), value.Int64())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -23,9 +23,9 @@ type AddrAndAmount struct {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// NeoContractHash is a hash of the NEO native contract.
|
// NeoContractHash is a hash of the NEO native contract.
|
||||||
NeoContractHash, _ = util.Uint160DecodeStringLE("9bde8f209c88dd0e7ca3bf0af0f476cdd8207789")
|
NeoContractHash, _ = util.Uint160DecodeStringBE("25059ecb4878d3a875f91c51ceded330d4575fde")
|
||||||
// GasContractHash is a hash of the GAS native contract.
|
// GasContractHash is a hash of the GAS native contract.
|
||||||
GasContractHash, _ = util.Uint160DecodeStringLE("8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b")
|
GasContractHash, _ = util.Uint160DecodeStringBE("bcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e66")
|
||||||
)
|
)
|
||||||
|
|
||||||
// NEP5Decimals invokes `decimals` NEP5 method on a specified contract.
|
// NEP5Decimals invokes `decimals` NEP5 method on a specified contract.
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PolicyContractHash represents BE hash of native Policy contract.
|
// PolicyContractHash represents a hash of native Policy contract.
|
||||||
var PolicyContractHash = util.Uint160{154, 97, 164, 110, 236, 151, 184, 147, 6, 215, 206, 129, 241, 91, 70, 32, 145, 208, 9, 50}
|
var PolicyContractHash, _ = util.Uint160DecodeStringBE("e9ff4ca7cc252e1dfddb26315869cd79505906ce")
|
||||||
|
|
||||||
// GetMaxTransactionsPerBlock invokes `getMaxTransactionsPerBlock` method on a
|
// GetMaxTransactionsPerBlock invokes `getMaxTransactionsPerBlock` method on a
|
||||||
// native Policy contract.
|
// native Policy contract.
|
||||||
|
|
|
@ -52,7 +52,7 @@ type rpcTestCase struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const testContractHash = "36c3b0c85d98607db00b711885ec3e411d9b1672"
|
const testContractHash = "36c3b0c85d98607db00b711885ec3e411d9b1672"
|
||||||
const deploymentTxHash = "dcf4fe429ec84947361c86c2192b14641be7f0c6e2bdf8d150fad731160ed386"
|
const deploymentTxHash = "ef4209bc06e1d8412995c645a8497d3e2c9a05ca52236de94297c6db9c3e94d0"
|
||||||
|
|
||||||
var rpcTestCases = map[string][]rpcTestCase{
|
var rpcTestCases = map[string][]rpcTestCase{
|
||||||
"getapplicationlog": {
|
"getapplicationlog": {
|
||||||
|
|
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
Loading…
Add table
Reference in a new issue