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 (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
// 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 (
|
||||
"context"
|
||||
"crypto/elliptic"
|
||||
"errors"
|
||||
"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/fee"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
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/storage"
|
||||
"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"
|
||||
)
|
||||
|
||||
|
@ -206,65 +198,3 @@ func storageFind(ic *interop.Context) error {
|
|||
|
||||
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) {
|
||||
_, ic, bc := createVM(t)
|
||||
|
||||
|
|
|
@ -33,9 +33,9 @@ var systemInterops = []interop.Function{
|
|||
{Name: interopnames.SystemContractCall, Func: contract.Call, Price: 1 << 15,
|
||||
RequiredFlags: callflag.ReadStates | callflag.AllowCall, ParamCount: 4},
|
||||
{Name: interopnames.SystemContractCallNative, Func: native.Call, Price: 0, ParamCount: 1},
|
||||
{Name: interopnames.SystemContractCreateMultisigAccount, Func: contractCreateMultisigAccount, Price: 0, ParamCount: 2},
|
||||
{Name: interopnames.SystemContractCreateStandardAccount, Func: contractCreateStandardAccount, Price: 0, ParamCount: 1},
|
||||
{Name: interopnames.SystemContractGetCallFlags, Func: contractGetCallFlags, Price: 1 << 10},
|
||||
{Name: interopnames.SystemContractCreateMultisigAccount, Func: contract.CreateMultisigAccount, Price: 0, ParamCount: 2},
|
||||
{Name: interopnames.SystemContractCreateStandardAccount, Func: contract.CreateStandardAccount, Price: 0, ParamCount: 1},
|
||||
{Name: interopnames.SystemContractGetCallFlags, Func: contract.GetCallFlags, Price: 1 << 10},
|
||||
{Name: interopnames.SystemContractNativeOnPersist, Func: native.OnPersist, 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},
|
||||
|
|
Loading…
Reference in a new issue