forked from TrueCloudLab/neoneo-go
core: move contract-related interop code into appropriate package
And move one of the tests with it.
This commit is contained in:
parent
10f94e6119
commit
209b977e9a
6 changed files with 106 additions and 81 deletions
71
pkg/core/interop/contract/account.go
Normal file
71
pkg/core/interop/contract/account.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package contract
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/elliptic"
|
||||||
|
"errors"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateMultisigAccount calculates multisig contract scripthash for a
|
||||||
|
// given m and a set of public keys.
|
||||||
|
func CreateMultisigAccount(ic *interop.Context) error {
|
||||||
|
m := ic.VM.Estack().Pop().BigInt()
|
||||||
|
mu64 := m.Uint64()
|
||||||
|
if !m.IsUint64() || mu64 > math.MaxInt32 {
|
||||||
|
return errors.New("m must be positive and fit int32")
|
||||||
|
}
|
||||||
|
arr := ic.VM.Estack().Pop().Array()
|
||||||
|
pubs := make(keys.PublicKeys, len(arr))
|
||||||
|
for i, pk := range arr {
|
||||||
|
p, err := keys.NewPublicKeyFromBytes(pk.Value().([]byte), elliptic.P256())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pubs[i] = p
|
||||||
|
}
|
||||||
|
var invokeFee int64
|
||||||
|
if ic.IsHardforkEnabled(config.HFAspidochelone) {
|
||||||
|
invokeFee = fee.ECDSAVerifyPrice * int64(len(pubs))
|
||||||
|
} else {
|
||||||
|
invokeFee = 1 << 8
|
||||||
|
}
|
||||||
|
invokeFee *= ic.BaseExecFee()
|
||||||
|
if !ic.VM.AddGas(invokeFee) {
|
||||||
|
return errors.New("gas limit exceeded")
|
||||||
|
}
|
||||||
|
script, err := smartcontract.CreateMultiSigRedeemScript(int(mu64), pubs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ic.VM.Estack().PushItem(stackitem.NewByteArray(hash.Hash160(script).BytesBE()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateStandardAccount calculates contract scripthash for a given public key.
|
||||||
|
func CreateStandardAccount(ic *interop.Context) error {
|
||||||
|
h := ic.VM.Estack().Pop().Bytes()
|
||||||
|
p, err := keys.NewPublicKeyFromBytes(h, elliptic.P256())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var invokeFee int64
|
||||||
|
if ic.IsHardforkEnabled(config.HFAspidochelone) {
|
||||||
|
invokeFee = fee.ECDSAVerifyPrice
|
||||||
|
} else {
|
||||||
|
invokeFee = 1 << 8
|
||||||
|
}
|
||||||
|
invokeFee *= ic.BaseExecFee()
|
||||||
|
if !ic.VM.AddGas(invokeFee) {
|
||||||
|
return errors.New("gas limit exceeded")
|
||||||
|
}
|
||||||
|
ic.VM.Estack().PushItem(stackitem.NewByteArray(p.GetScriptHash().BytesBE()))
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package contract
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
||||||
|
@ -172,3 +173,9 @@ func CallFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contract
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCallFlags returns current context calling flags.
|
||||||
|
func GetCallFlags(ic *interop.Context) error {
|
||||||
|
ic.VM.Estack().PushItem(stackitem.NewBigInteger(big.NewInt(int64(ic.VM.Context().GetCallFlags()))))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
25
pkg/core/interop/contract/call_test.go
Normal file
25
pkg/core/interop/contract/call_test.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package contract_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||||
|
"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/opcode"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetCallFlags(t *testing.T) {
|
||||||
|
bc, _ := chain.NewSingle(t)
|
||||||
|
ic := bc.GetTestVM(trigger.Application, &transaction.Transaction{}, &block.Block{})
|
||||||
|
|
||||||
|
ic.VM.LoadScriptWithHash([]byte{byte(opcode.RET)}, util.Uint160{1, 2, 3}, callflag.All)
|
||||||
|
require.NoError(t, contract.GetCallFlags(ic))
|
||||||
|
require.Equal(t, int64(callflag.All), ic.VM.Estack().Pop().Value().(*big.Int).Int64())
|
||||||
|
}
|
|
@ -2,23 +2,15 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/elliptic"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
istorage "github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
|
istorage "github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"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/smartcontract"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -206,65 +198,3 @@ func storageFind(ic *interop.Context) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// contractCreateMultisigAccount calculates multisig contract scripthash for a
|
|
||||||
// given m and a set of public keys.
|
|
||||||
func contractCreateMultisigAccount(ic *interop.Context) error {
|
|
||||||
m := ic.VM.Estack().Pop().BigInt()
|
|
||||||
mu64 := m.Uint64()
|
|
||||||
if !m.IsUint64() || mu64 > math.MaxInt32 {
|
|
||||||
return errors.New("m must be positive and fit int32")
|
|
||||||
}
|
|
||||||
arr := ic.VM.Estack().Pop().Array()
|
|
||||||
pubs := make(keys.PublicKeys, len(arr))
|
|
||||||
for i, pk := range arr {
|
|
||||||
p, err := keys.NewPublicKeyFromBytes(pk.Value().([]byte), elliptic.P256())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
pubs[i] = p
|
|
||||||
}
|
|
||||||
var invokeFee int64
|
|
||||||
if ic.IsHardforkEnabled(config.HFAspidochelone) {
|
|
||||||
invokeFee = fee.ECDSAVerifyPrice * int64(len(pubs))
|
|
||||||
} else {
|
|
||||||
invokeFee = 1 << 8
|
|
||||||
}
|
|
||||||
invokeFee *= ic.BaseExecFee()
|
|
||||||
if !ic.VM.AddGas(invokeFee) {
|
|
||||||
return errors.New("gas limit exceeded")
|
|
||||||
}
|
|
||||||
script, err := smartcontract.CreateMultiSigRedeemScript(int(mu64), pubs)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ic.VM.Estack().PushItem(stackitem.NewByteArray(hash.Hash160(script).BytesBE()))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// contractCreateStandardAccount calculates contract scripthash for a given public key.
|
|
||||||
func contractCreateStandardAccount(ic *interop.Context) error {
|
|
||||||
h := ic.VM.Estack().Pop().Bytes()
|
|
||||||
p, err := keys.NewPublicKeyFromBytes(h, elliptic.P256())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var invokeFee int64
|
|
||||||
if ic.IsHardforkEnabled(config.HFAspidochelone) {
|
|
||||||
invokeFee = fee.ECDSAVerifyPrice
|
|
||||||
} else {
|
|
||||||
invokeFee = 1 << 8
|
|
||||||
}
|
|
||||||
invokeFee *= ic.BaseExecFee()
|
|
||||||
if !ic.VM.AddGas(invokeFee) {
|
|
||||||
return errors.New("gas limit exceeded")
|
|
||||||
}
|
|
||||||
ic.VM.Estack().PushItem(stackitem.NewByteArray(p.GetScriptHash().BytesBE()))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// contractGetCallFlags returns current context calling flags.
|
|
||||||
func contractGetCallFlags(ic *interop.Context) error {
|
|
||||||
ic.VM.Estack().PushItem(stackitem.NewBigInteger(big.NewInt(int64(ic.VM.Context().GetCallFlags()))))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -706,14 +706,6 @@ func TestContractCall(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContractGetCallFlags(t *testing.T) {
|
|
||||||
v, ic, _ := createVM(t)
|
|
||||||
|
|
||||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, util.Uint160{1, 2, 3}, callflag.All)
|
|
||||||
require.NoError(t, contractGetCallFlags(ic))
|
|
||||||
require.Equal(t, int64(callflag.All), v.Estack().Pop().Value().(*big.Int).Int64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRuntimeCheckWitness(t *testing.T) {
|
func TestRuntimeCheckWitness(t *testing.T) {
|
||||||
_, ic, bc := createVM(t)
|
_, ic, bc := createVM(t)
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,9 @@ var systemInterops = []interop.Function{
|
||||||
{Name: interopnames.SystemContractCall, Func: contract.Call, Price: 1 << 15,
|
{Name: interopnames.SystemContractCall, Func: contract.Call, Price: 1 << 15,
|
||||||
RequiredFlags: callflag.ReadStates | callflag.AllowCall, ParamCount: 4},
|
RequiredFlags: callflag.ReadStates | callflag.AllowCall, ParamCount: 4},
|
||||||
{Name: interopnames.SystemContractCallNative, Func: native.Call, Price: 0, ParamCount: 1},
|
{Name: interopnames.SystemContractCallNative, Func: native.Call, Price: 0, ParamCount: 1},
|
||||||
{Name: interopnames.SystemContractCreateMultisigAccount, Func: contractCreateMultisigAccount, Price: 0, ParamCount: 2},
|
{Name: interopnames.SystemContractCreateMultisigAccount, Func: contract.CreateMultisigAccount, Price: 0, ParamCount: 2},
|
||||||
{Name: interopnames.SystemContractCreateStandardAccount, Func: contractCreateStandardAccount, Price: 0, ParamCount: 1},
|
{Name: interopnames.SystemContractCreateStandardAccount, Func: contract.CreateStandardAccount, Price: 0, ParamCount: 1},
|
||||||
{Name: interopnames.SystemContractGetCallFlags, Func: contractGetCallFlags, Price: 1 << 10},
|
{Name: interopnames.SystemContractGetCallFlags, Func: contract.GetCallFlags, Price: 1 << 10},
|
||||||
{Name: interopnames.SystemContractNativeOnPersist, Func: native.OnPersist, Price: 0, RequiredFlags: callflag.States},
|
{Name: interopnames.SystemContractNativeOnPersist, Func: native.OnPersist, Price: 0, RequiredFlags: callflag.States},
|
||||||
{Name: interopnames.SystemContractNativePostPersist, Func: native.PostPersist, Price: 0, RequiredFlags: callflag.States},
|
{Name: interopnames.SystemContractNativePostPersist, Func: native.PostPersist, Price: 0, RequiredFlags: callflag.States},
|
||||||
{Name: interopnames.SystemCryptoCheckMultisig, Func: crypto.ECDSASecp256r1CheckMultisig, Price: 0, ParamCount: 2},
|
{Name: interopnames.SystemCryptoCheckMultisig, Func: crypto.ECDSASecp256r1CheckMultisig, Price: 0, ParamCount: 2},
|
||||||
|
|
Loading…
Reference in a new issue