smartcontract

package
v0.0.0-...-886a677 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 8, 2024 License: MIT Imports: 20 Imported by: 5

Documentation

Overview

Package smartcontract contains functions to deal with widely used scripts and NEP-14 Parameters. Neo is all about various executed code, verifications and executions of transactions need NeoVM code and this package simplifies creating it for common tasks like multisignature verification scripts or transaction entry scripts that call previously deployed contracts. Another problem related to scripts and invocations is that RPC invocations use JSONized NEP-14 parameters, so this package provides types and methods to deal with that too.

Index

Examples

Constants

View Source
const (
	Hash160Len   = util.Uint160Size
	Hash256Len   = util.Uint256Size
	PublicKeyLen = 33
	SignatureLen = keys.SignatureLen
)

Lengths (in bytes) of fixed-size types.

Variables

This section is empty.

Functions

func CreateCallAndPrefetchIteratorScript

func CreateCallAndPrefetchIteratorScript(contract util.Uint160, operation string, maxIteratorResultItems int, params ...any) ([]byte, error)

CreateCallAndPrefetchIteratorScript creates a script that calls 'operation' method of the 'contract' with the specified arguments. This method is expected to return an array of the first iterator items (up to maxIteratorResultItems, which cannot exceed VM limits) and, optionally, an iterator that then is traversed (using iterator.Next). The result of the script is an array containing extracted value elements and an iterator, if it can contain more items. If the iterator is present, it lies on top of the stack. Note, however, that if an iterator is returned, the number of remaining items can still be 0. This script should only be used for interactions with RPC server that have iterator sessions enabled.

func CreateCallAndUnwrapIteratorScript

func CreateCallAndUnwrapIteratorScript(contract util.Uint160, operation string, maxIteratorResultItems int, params ...any) ([]byte, error)

CreateCallAndUnwrapIteratorScript creates a script that calls 'operation' method of the 'contract' with the specified arguments. This method is expected to return an iterator that then is traversed (using iterator.Next) with values (iterator.Value) extracted and added into array. At most maxIteratorResultItems number of items is processed this way (and this number can't exceed VM limits), the result of the script is an array containing extracted value elements. This script can be useful for interactions with RPC server that have iterator sessions disabled.

func CreateCallScript

func CreateCallScript(contract util.Uint160, method string, params ...any) ([]byte, error)

CreateCallScript returns a script that calls contract's method with the specified parameters. Whatever this method returns remains on the stack. See also (*Builder).InvokeMethod.

func CreateCallWithAssertScript

func CreateCallWithAssertScript(contract util.Uint160, method string, params ...any) ([]byte, error)

CreateCallWithAssertScript returns a script that calls contract's method with the specified parameters expecting a Boolean value to be return that then is used for ASSERT. See also (*Builder).InvokeWithAssert.

func CreateDefaultMultiSigRedeemScript

func CreateDefaultMultiSigRedeemScript(publicKeys keys.PublicKeys) ([]byte, error)

CreateDefaultMultiSigRedeemScript creates an "m out of n" type verification script using publicKeys length with the default BFT assumptions of (n - (n-1)/3) for m.

func CreateMajorityMultiSigRedeemScript

func CreateMajorityMultiSigRedeemScript(publicKeys keys.PublicKeys) ([]byte, error)

CreateMajorityMultiSigRedeemScript creates an "m out of n" type verification script using publicKeys length with m set to majority.

func CreateMultiSigRedeemScript

func CreateMultiSigRedeemScript(m int, publicKeys keys.PublicKeys) ([]byte, error)

CreateMultiSigRedeemScript creates an "m out of n" type verification script where n is the length of publicKeys.

func ExpandParameterToEmitable

func ExpandParameterToEmitable(param Parameter) (any, error)

ExpandParameterToEmitable converts a parameter to a type which can be handled as an array item by emit.Array. It correlates with the way an RPC server handles FuncParams for invoke* calls inside the request.ExpandArrayIntoScript function.

func GetDefaultHonestNodeCount

func GetDefaultHonestNodeCount(n int) int

GetDefaultHonestNodeCount returns minimum number of honest nodes required for network of size n.

func GetMajorityHonestNodeCount

func GetMajorityHonestNodeCount(n int) int

GetMajorityHonestNodeCount returns minimum number of honest nodes required for majority-style agreement.

Types

type Builder

type Builder struct {
	// contains filtered or unexported fields
}

Builder is used to create arbitrary scripts from the set of methods it provides. Each method emits some set of opcodes performing an action and (in most cases) returning a result. These chunks of code can be composed together to perform several actions in the same script (and therefore in the same transaction), but the end result (in terms of state changes and/or resulting items) of the script totally depends on what it contains and that's the responsibility of the Builder user. Builder is mostly used to create transaction scripts (also known as "entry scripts"), so the set of methods it exposes is tailored to this model of use and any calls emitted don't limit flags in any way (always use callflag.All).

When using this API keep in mind that the resulting script can't be larger than 64K (transaction.MaxScriptLength) to be used as a transaction entry script and it can't have more than 2048 elements on the stack. Technically, this limits the number of calls that can be made to a lesser value because invocations use the same stack too (the exact number depends on methods and parameters).

This API is not (and won't be) suitable to create complex scripts that use returned values as parameters to other calls or perform loops or do any other things that can be done in NeoVM. This hardly can be expressed in an API like this, so if you need more than that and if you're ready to work with bare NeoVM instructions please refer to emit and opcode packages.

Example
package main

import (
	"context"
	"encoding/hex"

	"github.com/epicchainlabs/epicchain-go/pkg/rpcclient"
	"github.com/epicchainlabs/epicchain-go/pkg/rpcclient/actor"
	"github.com/epicchainlabs/epicchain-go/pkg/rpcclient/gas"
	"github.com/epicchainlabs/epicchain-go/pkg/rpcclient/neo"
	"github.com/epicchainlabs/epicchain-go/pkg/smartcontract"
	"github.com/epicchainlabs/epicchain-go/pkg/util"
	"github.com/epicchainlabs/epicchain-go/pkg/wallet"
)

func main() {
	// No error checking done at all, intentionally.
	w, _ := wallet.NewWalletFromFile("somewhere")
	defer w.Close()

	c, _ := rpcclient.New(context.Background(), "url", rpcclient.Options{})

	// Assuming there is one Account inside.
	a, _ := actor.NewSimple(c, w.Accounts[0])

	pKey, _ := hex.DecodeString("03d9e8b16bd9b22d3345d6d4cde31be1c3e1d161532e3d0ccecb95ece2eb58336e") // Public key.

	b := smartcontract.NewBuilder()
	// Transfer + vote in a single script with each action leaving return value on the stack.
	b.InvokeMethod(neo.Hash, "transfer", a.Sender(), util.Uint160{0xff}, 1, nil)
	b.InvokeMethod(neo.Hash, "vote", pKey)
	script, _ := b.Script()

	// Actor has an Invoker inside, so we can perform test invocation using the script.
	res, _ := a.Run(script)
	if res.State != "HALT" || len(res.Stack) != 2 {
		panic("failed") // The script failed completely or didn't return proper number of return values.
	}

	transferResult, _ := res.Stack[0].TryBool()
	voteResult, _ := res.Stack[1].TryBool()

	if !transferResult {
		panic("transfer failed")
	}
	if !voteResult {
		panic("vote failed")
	}

	b.Reset() // Copy the old script above if you need it!

	// Multiple transfers of different tokens in a single script. If any of
	// them fails whole script fails.
	b.InvokeWithAssert(neo.Hash, "transfer", a.Sender(), util.Uint160{0x70}, 1, nil)
	b.InvokeWithAssert(gas.Hash, "transfer", a.Sender(), util.Uint160{0x71}, 100000, []byte("data"))
	b.InvokeWithAssert(neo.Hash, "transfer", a.Sender(), util.Uint160{0x72}, 1, nil)
	script, _ = b.Script()

	// Now send a transaction with this script via an RPC node.
	txid, vub, _ := a.SendRun(script)
	_ = txid
	_ = vub
}
Output:

func NewBuilder

func NewBuilder() *Builder

NewBuilder creates a new Builder instance.

func (*Builder) Assert

func (b *Builder) Assert()

Assert emits an ASSERT opcode that expects a Boolean value to be on the stack, checks if it's true and aborts the transaction if it's not.

func (*Builder) InvokeMethod

func (b *Builder) InvokeMethod(contract util.Uint160, method string, params ...any)

InvokeMethod is the most generic contract method invoker, the code it produces packs all of the arguments given into an array and calls some method of the contract. It accepts as parameters everything that emit.Array accepts. The correctness of this invocation (number and type of parameters) is out of scope of this method, as well as return value, if contract's method returns something this value just remains on the execution stack.

func (*Builder) InvokeWithAssert

func (b *Builder) InvokeWithAssert(contract util.Uint160, method string, params ...any)

InvokeWithAssert emits an invocation of the method (see InvokeMethod) with an ASSERT after the invocation. The presumption is that the method called returns a Boolean value signalling the success or failure of the operation. This pattern is pretty common, NEP-11 or NEP-17 'transfer' methods do exactly that as well as NEO's 'vote'. The ASSERT then allow to simplify transaction status checking, if action is successful then transaction is successful as well, if it went wrong than whole transaction fails (ends with vmstate.FAULT).

func (*Builder) Len

func (b *Builder) Len() int

Len returns the current length of the script. It's useful to perform script length checks (wrt transaction.MaxScriptLength limit) while building the script.

func (*Builder) Reset

func (b *Builder) Reset()

Reset resets the Builder, allowing to reuse the same script buffer (but previous script will be overwritten there).

func (*Builder) Script

func (b *Builder) Script() ([]byte, error)

Script return current script, you can't use Builder after invoking this method unless you Reset it.

type Convertible

type Convertible interface {
	ToSCParameter() (Parameter, error)
}

Convertible is something that can be converted to Parameter.

type ParamType

type ParamType int

ParamType represents the Type of the smart contract parameter.

const (
	UnknownType          ParamType = -1
	AnyType              ParamType = 0x00
	BoolType             ParamType = 0x10
	IntegerType          ParamType = 0x11
	ByteArrayType        ParamType = 0x12
	StringType           ParamType = 0x13
	Hash160Type          ParamType = 0x14
	Hash256Type          ParamType = 0x15
	PublicKeyType        ParamType = 0x16
	SignatureType        ParamType = 0x17
	ArrayType            ParamType = 0x20
	MapType              ParamType = 0x22
	InteropInterfaceType ParamType = 0x30
	VoidType             ParamType = 0xff
)

A list of supported smart contract parameter types.

func ConvertToParamType

func ConvertToParamType(val int) (ParamType, error)

ConvertToParamType converts the provided value to the parameter type if it's a valid type.

func ParseParamType

func ParseParamType(typ string) (ParamType, error)

ParseParamType is a user-friendly string to ParamType converter, it's case-insensitive and makes the following conversions:

signature -> SignatureType
bool, boolean -> BoolType
int, integer -> IntegerType
hash160 -> Hash160Type
hash256 -> Hash256Type
bytes, bytearray, filebytes -> ByteArrayType
key, publickey -> PublicKeyType
string -> StringType
array, struct -> ArrayType
map -> MapType
interopinterface -> InteropInterfaceType
void -> VoidType

anything else generates an error.

func (ParamType) ConvertToStackitemType

func (pt ParamType) ConvertToStackitemType() stackitem.Type

ConvertToStackitemType converts ParamType to corresponding Stackitem.Type.

func (*ParamType) DecodeBinary

func (pt *ParamType) DecodeBinary(r *io.BinReader)

DecodeBinary implements the io.Serializable interface.

func (ParamType) EncodeBinary

func (pt ParamType) EncodeBinary(w *io.BinWriter)

EncodeBinary implements the io.Serializable interface.

func (ParamType) EncodeDefaultValue

func (pt ParamType) EncodeDefaultValue(w *io.BinWriter)

EncodeDefaultValue writes a script to push the default parameter value onto the evaluation stack into the given writer. It's mostly useful for constructing dummy invocation scripts when parameter types are known, but they can't be filled in. A best effort approach is used, it can't be perfect since for many types the exact values can be arbitrarily long, but it tries to do something reasonable in each case. For signatures, strings, arrays and "any" type a 64-byte zero-filled value is used, hash160 and hash256 use appropriately sized values, public key is represented by 33-byte value while 32 bytes are used for integer and a simple push+convert is used for boolean. Other types produce no code at all.

func (ParamType) MarshalJSON

func (pt ParamType) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface.

func (ParamType) MarshalYAML

func (pt ParamType) MarshalYAML() (any, error)

MarshalYAML implements the YAML Marshaler interface.

func (ParamType) Match

func (pt ParamType) Match(v stackitem.Item) bool

func (ParamType) String

func (pt ParamType) String() string

String implements the stringer interface.

func (*ParamType) UnmarshalJSON

func (pt *ParamType) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface.

func (*ParamType) UnmarshalYAML

func (pt *ParamType) UnmarshalYAML(unmarshal func(any) error) error

UnmarshalYAML implements the YAML Unmarshaler interface.

type Parameter

type Parameter struct {
	// Type of the parameter.
	Type ParamType `json:"type"`
	// The actual value of the parameter.
	Value any `json:"value"`
}

Parameter represents a smart contract parameter.

func NewParameter

func NewParameter(t ParamType) Parameter

NewParameter returns a Parameter with a proper initialized Value of the given ParamType.

func NewParameterFromString

func NewParameterFromString(in string) (*Parameter, error)

NewParameterFromString returns a new Parameter initialized from the given string in neo-go-specific format. It is intended to be used in user-facing interfaces and has some heuristics in it to simplify parameter passing. The exact syntax is documented in the cli documentation.

func NewParameterFromValue

func NewParameterFromValue(value any) (Parameter, error)

NewParameterFromValue infers Parameter type from the value given and adjusts the value if needed. It does not copy the value if it can avoid doing so. All regular integers, util.*, keys.PublicKey*, string and bool types are supported, slice of byte slices is accepted and converted as well.

func NewParametersFromValues

func NewParametersFromValues(values ...any) ([]Parameter, error)

NewParametersFromValues is similar to NewParameterFromValue except that it works with multiple values and returns a simple slice of Parameter.

func (Parameter) MarshalJSON

func (p Parameter) MarshalJSON() ([]byte, error)

MarshalJSON implements the Marshaler interface.

func (*Parameter) ToStackItem

func (p *Parameter) ToStackItem() (stackitem.Item, error)

ToStackItem converts smartcontract parameter to stackitem.Item.

func (*Parameter) UnmarshalJSON

func (p *Parameter) UnmarshalJSON(data []byte) (err error)

UnmarshalJSON implements the Unmarshaler interface.

type ParameterPair

type ParameterPair struct {
	Key   Parameter `json:"key"`
	Value Parameter `json:"value"`
}

ParameterPair represents a key-value pair, a slice of which is stored in MapType Parameter.

Directories

Path Synopsis
standard
Package standard contains interfaces for well-defined standards and a function for checking if an arbitrary manifest complies with them.
Package standard contains interfaces for well-defined standards and a function for checking if an arbitrary manifest complies with them.
Package zkpbinding contains a set of helper functions aimed to generate and interact with Verifier smart contract written in Go and using Groth-16 proving system over BLS12-381 elliptic curve to verify proofs.
Package zkpbinding contains a set of helper functions aimed to generate and interact with Verifier smart contract written in Go and using Groth-16 proving system over BLS12-381 elliptic curve to verify proofs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL