122 lines
4.6 KiB
Go
122 lines
4.6 KiB
Go
package actor_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"os"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/policy"
|
|
sccontext "github.com/nspcc-dev/neo-go/pkg/smartcontract/context"
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
|
)
|
|
|
|
func ExampleActor() {
|
|
// No error checking done at all, intentionally.
|
|
w, _ := wallet.NewWalletFromFile("somewhere")
|
|
defer w.Close()
|
|
|
|
c, _ := rpcclient.New(context.Background(), "url", rpcclient.Options{})
|
|
|
|
// Create a simple CalledByEntry-scoped actor (assuming there are accounts
|
|
// inside the wallet).
|
|
a, _ := actor.NewSimple(c, w.Accounts[0])
|
|
|
|
customContract := util.Uint160{9, 8, 7}
|
|
// Actor has an Invoker inside, so we can perform test invocations, it will
|
|
// have a signer with the first wallet account and CalledByEntry scope.
|
|
res, _ := a.Call(customContract, "method", 1, 2, 3)
|
|
if res.State != vmstate.Halt.String() {
|
|
panic("failed")
|
|
}
|
|
// All of the side-effects in res can be analyzed.
|
|
|
|
// Now we want to send the same invocation in a transaction, but we already
|
|
// have the script and a proper system fee for it, therefore SendUncheckedRun
|
|
// can be used.
|
|
txid, vub, _ := a.SendUncheckedRun(res.Script, res.GasConsumed, nil, nil)
|
|
_ = txid
|
|
_ = vub
|
|
// You need to wait for it to persist and then check the on-chain result of it.
|
|
|
|
// Now we want to send some transaction, but give it a priority by increasing
|
|
// its network fee, this can be done with Tuned APIs.
|
|
txid, vub, _ = a.SendTunedCall(customContract, "method", nil, func(r *result.Invoke, t *transaction.Transaction) error {
|
|
// This code is run after the test-invocation done by *Call methods.
|
|
// Reuse the default function to check for HALT execution state.
|
|
err := actor.DefaultCheckerModifier(r, t)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Some additional checks can be performed right here, but we only
|
|
// want to raise the network fee by ~20%.
|
|
t.NetworkFee += (t.NetworkFee / 5)
|
|
return nil
|
|
}, 1, 2, 3)
|
|
_ = txid
|
|
_ = vub
|
|
|
|
// Actor can be used for higher-level wrappers as well, if we want to interact with
|
|
// NEO then [neo] package can accept our Actor and allow to easily use NEO methods.
|
|
neoContract := neo.New(a)
|
|
balance, _ := neoContract.BalanceOf(a.Sender())
|
|
_ = balance
|
|
|
|
// Now suppose the second wallet account is a committee account. We want to
|
|
// create and sign transactions for committee, but use the first account as
|
|
// a sender (because committee account has no GAS). We at the same time want
|
|
// to make all transactions using this actor high-priority ones, because
|
|
// committee can use this attribute.
|
|
|
|
// Get the default options to have CheckerModifier/Modifier set up correctly.
|
|
opts := actor.NewDefaultOptions()
|
|
// And override attributes.
|
|
opts.Attributes = []transaction.Attribute{{Type: transaction.HighPriority}}
|
|
|
|
// Create an Actor.
|
|
a, _ = actor.NewTuned(c, []actor.SignerAccount{{
|
|
// Sender, regular account with None scope.
|
|
Signer: transaction.Signer{
|
|
Account: w.Accounts[0].ScriptHash(),
|
|
Scopes: transaction.None,
|
|
},
|
|
Account: w.Accounts[0],
|
|
}, {
|
|
// Commmitee.
|
|
Signer: transaction.Signer{
|
|
Account: w.Accounts[1].ScriptHash(),
|
|
Scopes: transaction.CalledByEntry,
|
|
},
|
|
Account: w.Accounts[1],
|
|
}}, opts)
|
|
|
|
// Use policy contract wrapper to simplify things. All changes in the
|
|
// Policy contract are made by the committee.
|
|
policyContract := policy.New(a)
|
|
|
|
// Create a transaction to set storage price, it'll be high-priority and have two
|
|
// signers from above. Committee is a multisignature account, so we can't sign/send
|
|
// it right away, w.Accounts[1] has only one public key. Therefore, we need to
|
|
// create a partially signed transaction and save it, then collect other signatures
|
|
// and send.
|
|
tx, _ := policyContract.SetStoragePriceUnsigned(10)
|
|
|
|
net := a.GetNetwork()
|
|
scCtx := sccontext.NewParameterContext(sccontext.TransactionType, net, tx)
|
|
sign := w.Accounts[0].SignHashable(net, tx)
|
|
_ = scCtx.AddSignature(w.Accounts[0].ScriptHash(), w.Accounts[0].Contract, w.Accounts[0].PublicKey(), sign)
|
|
|
|
sign = w.Accounts[1].SignHashable(net, tx)
|
|
_ = scCtx.AddSignature(w.Accounts[1].ScriptHash(), w.Accounts[1].Contract, w.Accounts[1].PublicKey(), sign)
|
|
|
|
data, _ := json.Marshal(scCtx)
|
|
_ = os.WriteFile("tx.json", data, 0644)
|
|
|
|
// Signature collection is out of scope, usually it's manual for cases like this.
|
|
}
|