eeb439f548
Network server constructor reads config.Version variable, and testcli.DeployContract writes dummy config.Version which causes race in tests. Avoid this race by moving config.Version initialisation to a separate package and perform it inside test packages init(). Close #3011, close #3017. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
144 lines
4.5 KiB
Go
144 lines
4.5 KiB
Go
package testchain
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
gio "io"
|
|
"strings"
|
|
|
|
clisc "github.com/nspcc-dev/neo-go/cli/smartcontract"
|
|
"github.com/nspcc-dev/neo-go/internal/versionutil"
|
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
|
"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/native"
|
|
"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/hash"
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
)
|
|
|
|
// Ledger is an interface that abstracts the implementation of the blockchain.
|
|
type Ledger interface {
|
|
BlockHeight() uint32
|
|
FeePerByte() int64
|
|
GetBaseExecFee() int64
|
|
GetHeader(hash util.Uint256) (*block.Header, error)
|
|
GetHeaderHash(uint32) util.Uint256
|
|
HeaderHeight() uint32
|
|
ManagementContractHash() util.Uint160
|
|
}
|
|
|
|
var (
|
|
ownerHash = MultisigScriptHash()
|
|
ownerScript = MultisigVerificationScript()
|
|
)
|
|
|
|
// NewTransferFromOwner returns a transaction transferring funds from NEO and GAS owner.
|
|
func NewTransferFromOwner(bc Ledger, contractHash, to util.Uint160, amount int64,
|
|
nonce, validUntil uint32) (*transaction.Transaction, error) {
|
|
script, err := smartcontract.CreateCallWithAssertScript(contractHash, "transfer", ownerHash, to, amount, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tx := transaction.New(script, 11000000)
|
|
tx.ValidUntilBlock = validUntil
|
|
tx.Nonce = nonce
|
|
tx.Signers = []transaction.Signer{{
|
|
Account: ownerHash,
|
|
Scopes: transaction.CalledByEntry,
|
|
AllowedContracts: nil,
|
|
AllowedGroups: nil,
|
|
}}
|
|
return tx, SignTx(bc, tx)
|
|
}
|
|
|
|
// NewDeployTx returns a new deployment transaction for a contract with the source from r and a name equal to
|
|
// the filename without '.go' suffix.
|
|
func NewDeployTx(bc Ledger, name string, sender util.Uint160, r gio.Reader, confFile *string) (*transaction.Transaction, util.Uint160, []byte, error) {
|
|
// nef.NewFile() cares about version a lot.
|
|
config.Version = versionutil.TestVersion
|
|
|
|
o := &compiler.Options{
|
|
Name: strings.TrimSuffix(name, ".go"),
|
|
NoStandardCheck: true,
|
|
NoEventsCheck: true,
|
|
}
|
|
if confFile != nil {
|
|
conf, err := clisc.ParseContractConfig(*confFile)
|
|
if err != nil {
|
|
return nil, util.Uint160{}, nil, fmt.Errorf("failed to parse configuration: %w", err)
|
|
}
|
|
o.Name = conf.Name
|
|
o.SourceURL = conf.SourceURL
|
|
o.ContractEvents = conf.Events
|
|
o.DeclaredNamedTypes = conf.NamedTypes
|
|
o.ContractSupportedStandards = conf.SupportedStandards
|
|
o.Permissions = make([]manifest.Permission, len(conf.Permissions))
|
|
for i := range conf.Permissions {
|
|
o.Permissions[i] = manifest.Permission(conf.Permissions[i])
|
|
}
|
|
o.SafeMethods = conf.SafeMethods
|
|
o.Overloads = conf.Overloads
|
|
}
|
|
|
|
ne, di, err := compiler.CompileWithOptions(name, r, o)
|
|
if err != nil {
|
|
return nil, util.Uint160{}, nil, err
|
|
}
|
|
|
|
m, err := compiler.CreateManifest(di, o)
|
|
if err != nil {
|
|
return nil, util.Uint160{}, nil, fmt.Errorf("failed to create manifest: %w", err)
|
|
}
|
|
|
|
rawManifest, err := json.Marshal(m)
|
|
if err != nil {
|
|
return nil, util.Uint160{}, nil, err
|
|
}
|
|
neb, err := ne.Bytes()
|
|
if err != nil {
|
|
return nil, util.Uint160{}, nil, err
|
|
}
|
|
script, err := smartcontract.CreateCallScript(bc.ManagementContractHash(), "deploy", neb, rawManifest)
|
|
if err != nil {
|
|
return nil, util.Uint160{}, nil, err
|
|
}
|
|
|
|
tx := transaction.New(script, 100*native.GASFactor)
|
|
tx.Signers = []transaction.Signer{{Account: sender}}
|
|
h := state.CreateContractHash(tx.Sender(), ne.Checksum, m.Name)
|
|
|
|
return tx, h, ne.Script, nil
|
|
}
|
|
|
|
// SignTx signs the provided transactions with validator keys.
|
|
func SignTx(bc Ledger, txs ...*transaction.Transaction) error {
|
|
signTxGeneric(bc, Sign, ownerScript, txs...)
|
|
return nil
|
|
}
|
|
|
|
// SignTxCommittee signs transactions by committee.
|
|
func SignTxCommittee(bc Ledger, txs ...*transaction.Transaction) error {
|
|
signTxGeneric(bc, SignCommittee, CommitteeVerificationScript(), txs...)
|
|
return nil
|
|
}
|
|
|
|
func signTxGeneric(bc Ledger, sign func(hash.Hashable) []byte, verif []byte, txs ...*transaction.Transaction) {
|
|
for _, tx := range txs {
|
|
size := io.GetVarSize(tx)
|
|
netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), verif)
|
|
tx.NetworkFee += netFee
|
|
size += sizeDelta
|
|
tx.NetworkFee += int64(size) * bc.FeePerByte()
|
|
tx.Scripts = []transaction.Witness{{
|
|
InvocationScript: sign(tx),
|
|
VerificationScript: verif,
|
|
}}
|
|
}
|
|
}
|