github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/services/rpcsrv/params/txBuilder.go (about) 1 package params 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/nspcc-dev/neo-go/pkg/crypto/keys" 8 "github.com/nspcc-dev/neo-go/pkg/io" 9 "github.com/nspcc-dev/neo-go/pkg/smartcontract" 10 "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" 11 "github.com/nspcc-dev/neo-go/pkg/util" 12 "github.com/nspcc-dev/neo-go/pkg/vm/emit" 13 "github.com/nspcc-dev/neo-go/pkg/vm/opcode" 14 ) 15 16 // ExpandFuncParameterIntoScript pushes provided FuncParam parameter 17 // into the given buffer. 18 func ExpandFuncParameterIntoScript(script *io.BinWriter, fp FuncParam) error { 19 switch fp.Type { 20 case smartcontract.ByteArrayType: 21 str, err := fp.Value.GetBytesBase64() 22 if err != nil { 23 return err 24 } 25 emit.Bytes(script, str) 26 case smartcontract.SignatureType: 27 str, err := fp.Value.GetBytesBase64() 28 if err != nil { 29 return err 30 } 31 emit.Bytes(script, str) 32 case smartcontract.StringType: 33 str, err := fp.Value.GetString() 34 if err != nil { 35 return err 36 } 37 emit.String(script, str) 38 case smartcontract.Hash160Type: 39 hash, err := fp.Value.GetUint160FromHex() 40 if err != nil { 41 return err 42 } 43 emit.Bytes(script, hash.BytesBE()) 44 case smartcontract.Hash256Type: 45 hash, err := fp.Value.GetUint256() 46 if err != nil { 47 return err 48 } 49 emit.Bytes(script, hash.BytesBE()) 50 case smartcontract.PublicKeyType: 51 str, err := fp.Value.GetString() 52 if err != nil { 53 return err 54 } 55 key, err := keys.NewPublicKeyFromString(string(str)) 56 if err != nil { 57 return err 58 } 59 emit.Bytes(script, key.Bytes()) 60 case smartcontract.IntegerType: 61 bi, err := fp.Value.GetBigInt() 62 if err != nil { 63 return err 64 } 65 emit.BigInt(script, bi) 66 case smartcontract.BoolType: 67 val, err := fp.Value.GetBoolean() // not GetBooleanStrict(), because that's the way C# code works 68 if err != nil { 69 return errors.New("not a bool") 70 } 71 emit.Bool(script, val) 72 case smartcontract.ArrayType: 73 val, err := fp.Value.GetArray() 74 if err != nil { 75 return err 76 } 77 err = ExpandArrayIntoScriptAndPack(script, val) 78 if err != nil { 79 return err 80 } 81 case smartcontract.MapType: 82 val, err := fp.Value.GetArray() 83 if err != nil { 84 return err 85 } 86 err = ExpandMapIntoScriptAndPack(script, val) 87 if err != nil { 88 return err 89 } 90 case smartcontract.AnyType: 91 if fp.Value.IsNull() || len(fp.Value.RawMessage) == 0 { 92 emit.Opcodes(script, opcode.PUSHNULL) 93 } 94 default: 95 return fmt.Errorf("parameter type %v is not supported", fp.Type) 96 } 97 return script.Err 98 } 99 100 // ExpandArrayIntoScript pushes all FuncParam parameters from the given array 101 // into the given buffer in the reverse order. 102 func ExpandArrayIntoScript(script *io.BinWriter, slice []Param) error { 103 for j := len(slice) - 1; j >= 0; j-- { 104 fp, err := slice[j].GetFuncParam() 105 if err != nil { 106 return err 107 } 108 err = ExpandFuncParameterIntoScript(script, fp) 109 if err != nil { 110 return fmt.Errorf("param %d: %w", j, err) 111 } 112 } 113 return script.Err 114 } 115 116 // ExpandArrayIntoScriptAndPack expands provided array into script and packs the 117 // resulting items in the array. 118 func ExpandArrayIntoScriptAndPack(script *io.BinWriter, slice []Param) error { 119 if len(slice) == 0 { 120 emit.Opcodes(script, opcode.NEWARRAY0) 121 return script.Err 122 } 123 err := ExpandArrayIntoScript(script, slice) 124 if err != nil { 125 return err 126 } 127 emit.Int(script, int64(len(slice))) 128 emit.Opcodes(script, opcode.PACK) 129 return script.Err 130 } 131 132 // ExpandMapIntoScriptAndPack expands provided array of key-value items into script 133 // and packs the resulting pairs in the [stackitem.Map]. 134 func ExpandMapIntoScriptAndPack(script *io.BinWriter, slice []Param) error { 135 if len(slice) == 0 { 136 emit.Opcodes(script, opcode.NEWMAP) 137 return script.Err 138 } 139 for i := len(slice) - 1; i >= 0; i-- { 140 pair, err := slice[i].GetFuncParamPair() 141 if err != nil { 142 return err 143 } 144 err = ExpandFuncParameterIntoScript(script, pair.Value) 145 if err != nil { 146 return fmt.Errorf("map value %d: %w", i, err) 147 } 148 err = ExpandFuncParameterIntoScript(script, pair.Key) 149 if err != nil { 150 return fmt.Errorf("map key %d: %w", i, err) 151 } 152 } 153 emit.Int(script, int64(len(slice))) 154 emit.Opcodes(script, opcode.PACKMAP) 155 return script.Err 156 } 157 158 // CreateFunctionInvocationScript creates a script to invoke the given contract with 159 // the given parameters. 160 func CreateFunctionInvocationScript(contract util.Uint160, method string, param *Param) ([]byte, error) { 161 script := io.NewBufBinWriter() 162 if param == nil { 163 emit.Opcodes(script.BinWriter, opcode.NEWARRAY0) 164 } else if slice, err := param.GetArray(); err == nil { 165 err = ExpandArrayIntoScriptAndPack(script.BinWriter, slice) 166 if err != nil { 167 return nil, err 168 } 169 } else { 170 return nil, fmt.Errorf("failed to convert %s to script parameter", param) 171 } 172 173 emit.AppCallNoArgs(script.BinWriter, contract, method, callflag.All) 174 return script.Bytes(), nil 175 }