package invoke import ( "bytes" "crypto/ecdsa" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neofs-crypto" "github.com/nspcc-dev/neofs-node/pkg/morph/client" ) type ( // ChequeParams for CashOutCheque invocation. ChequeParams struct { ID []byte Amount int64 // Fixed8 User util.Uint160 LockAccount util.Uint160 } ) const ( // Extra SysFee for contract invocations. Contracts execute inner ring // invocations in two steps: collection and execution. At collection // step contract waits for (2\3*n + 1) invocations, and then in execution // stage contract actually makes changes in the contract storage. SysFee // for invocation calculated based on testinvoke which happens at collection // stage. Therefore client has to provide some extra SysFee to operate at // execution stage. Otherwise invocation will fail due to gas limit. extraFee = 1_5000_0000 // 1.5 Fixed8 gas // Different methods need different extra fee values, so with this // constants let's try to minimize spent GAS of inner ring node. feeHalfGas = 50_000_000 // 0.5 Fixed8 gas feeOneGas = feeHalfGas * 2 // 1.0 Fixed8 gas checkIsInnerRingMethod = "isInnerRing" innerRingListMethod = "innerRingList" chequeMethod = "cheque" ) // IsInnerRing returns true if 'key' is presented in inner ring list. func IsInnerRing(cli *client.Client, con util.Uint160, key *ecdsa.PublicKey) (bool, error) { if cli == nil { return false, client.ErrNilClient } pubKey := crypto.MarshalPublicKey(key) val, err := cli.TestInvoke(con, checkIsInnerRingMethod, pubKey) if err != nil { return false, err } isInnerRing, err := client.BoolFromStackItem(val[0]) if err != nil { return false, err } return isInnerRing, nil } // CashOutCheque invokes Cheque method. func CashOutCheque(cli *client.Client, con util.Uint160, p *ChequeParams) error { if cli == nil { return client.ErrNilClient } return cli.Invoke(con, extraFee, chequeMethod, p.ID, p.User.BytesBE(), p.Amount, p.LockAccount.BytesBE(), ) } // InnerRingIndex returns index of the `key` in the inner ring list from sidechain. // If key is not in the inner ring list, then returns `-1`. func InnerRingIndex(cli *client.Client, con util.Uint160, key *ecdsa.PublicKey) (int32, error) { if cli == nil { return 0, client.ErrNilClient } nodePublicKey := crypto.MarshalPublicKey(key) data, err := cli.TestInvoke(con, innerRingListMethod) if err != nil { return 0, err } irNodes, err := client.ArrayFromStackItem(data[0]) if err != nil { return 0, err } var result int32 = -1 for i := range irNodes { key, err := client.ArrayFromStackItem(irNodes[i]) if err != nil { return 0, err } keyValue, err := client.BytesFromStackItem(key[0]) if err != nil { return 0, err } if bytes.Equal(keyValue, nodePublicKey) { result = int32(i) break } } return result, nil }