Merge pull request #1762 from nspcc-dev/cli/files

cli: add `filebytes` parameter type
This commit is contained in:
Roman Khimov 2021-02-19 11:14:02 +03:00 committed by GitHub
commit 7f6a0fd98c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 34 additions and 9 deletions

View file

@ -210,6 +210,10 @@ func NewCommands() []cli.Command {
symbols around array values to denote array bounds. Nested arrays are also symbols around array values to denote array bounds. Nested arrays are also
supported. supported.
There is ability to provide an argument of 'bytearray' type via file. Use a
special 'filebytes' argument type for this with a filepath specified after
the colon, e.g. 'filebytes:my_file.txt'.
Given values are type-checked against given types with the following Given values are type-checked against given types with the following
restrictions applied: restrictions applied:
* 'signature' type values should be hex-encoded and have a (decoded) * 'signature' type values should be hex-encoded and have a (decoded)
@ -222,6 +226,7 @@ func NewCommands() []cli.Command {
* 'hash256' type values should be hex-encoded and have a (decoded) * 'hash256' type values should be hex-encoded and have a (decoded)
length of 32 bytes. length of 32 bytes.
* 'bytes' type values are any hex-encoded things. * 'bytes' type values are any hex-encoded things.
* 'filebytes' type values are filenames with the argument value inside.
* 'key' type values are hex-encoded marshalled public keys. * 'key' type values are hex-encoded marshalled public keys.
* 'string' type values are any valid UTF-8 strings. In the value's part of * 'string' type values are any valid UTF-8 strings. In the value's part of
the string the colon looses it's special meaning as a separator between the string the colon looses it's special meaning as a separator between
@ -250,6 +255,7 @@ func NewCommands() []cli.Command {
* 'bad' is a string with a value of 'bad' * 'bad' is a string with a value of 'bad'
* 'dead' is a byte array with a value of 'dead' * 'dead' is a byte array with a value of 'dead'
* 'string:dead' is a string with a value of 'dead' * 'string:dead' is a string with a value of 'dead'
* 'filebytes:my_data.txt' is bytes decoded from a content of my_data.txt
* 'AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y' is a hash160 with a value * 'AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y' is a hash160 with a value
of '23ba2703c53263e8d6e522dc32203339dcd8eee9' of '23ba2703c53263e8d6e522dc32203339dcd8eee9'
* '\4\2' is an integer with a value of 42 * '\4\2' is an integer with a value of 42

View file

@ -35,6 +35,9 @@ const (
VoidType ParamType = 0xff VoidType ParamType = 0xff
) )
// fileBytesParamType is a string representation of `filebytes` parameter type used in cli.
const fileBytesParamType string = "filebytes"
// validParamTypes contains a map of known ParamTypes // validParamTypes contains a map of known ParamTypes
var validParamTypes = map[ParamType]bool{ var validParamTypes = map[ParamType]bool{
UnknownType: true, UnknownType: true,
@ -142,7 +145,7 @@ func (pt *ParamType) DecodeBinary(r *io.BinReader) {
// int, integer -> IntegerType // int, integer -> IntegerType
// hash160 -> Hash160Type // hash160 -> Hash160Type
// hash256 -> Hash256Type // hash256 -> Hash256Type
// bytes, bytearray -> ByteArrayType // bytes, bytearray, filebytes -> ByteArrayType
// key, publickey -> PublicKeyType // key, publickey -> PublicKeyType
// string -> StringType // string -> StringType
// array, struct -> ArrayType // array, struct -> ArrayType
@ -162,7 +165,7 @@ func ParseParamType(typ string) (ParamType, error) {
return Hash160Type, nil return Hash160Type, nil
case "hash256": case "hash256":
return Hash256Type, nil return Hash256Type, nil
case "bytes", "bytearray", "bytestring": case "bytes", "bytearray", "bytestring", fileBytesParamType:
return ByteArrayType, nil return ByteArrayType, nil
case "key", "publickey": case "key", "publickey":
return PublicKeyType, nil return PublicKeyType, nil
@ -223,11 +226,7 @@ func adjustValToType(typ ParamType, val string) (interface{}, error) {
} }
return u, nil return u, nil
case ByteArrayType: case ByteArrayType:
b, err := hex.DecodeString(val) return hex.DecodeString(val)
if err != nil {
return nil, err
}
return b, nil
case PublicKeyType: case PublicKeyType:
pub, err := keys.NewPublicKeyFromString(val) pub, err := keys.NewPublicKeyFromString(val)
if err != nil { if err != nil {

View file

@ -59,7 +59,11 @@ func TestParseParamType(t *testing.T) {
}, { }, {
in: "qwerty", in: "qwerty",
err: true, err: true,
}} }, {
in: "filebytes",
out: ByteArrayType,
},
}
for _, inout := range inouts { for _, inout := range inouts {
out, err := ParseParamType(inout.in) out, err := ParseParamType(inout.in)
if inout.err { if inout.err {

View file

@ -7,6 +7,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"math" "math"
"math/bits" "math/bits"
"strconv" "strconv"
@ -387,6 +388,7 @@ func NewParameterFromString(in string) (*Parameter, error) {
escaped bool escaped bool
hadType bool hadType bool
res = &Parameter{} res = &Parameter{}
typStr string
) )
r = strings.NewReader(in) r = strings.NewReader(in)
for char, _, err = r.ReadRune(); err == nil && char != utf8.RuneError; char, _, err = r.ReadRune() { for char, _, err = r.ReadRune(); err == nil && char != utf8.RuneError; char, _, err = r.ReadRune() {
@ -395,7 +397,7 @@ func NewParameterFromString(in string) (*Parameter, error) {
continue continue
} }
if char == ':' && !escaped && !hadType { if char == ':' && !escaped && !hadType {
typStr := buf.String() typStr = buf.String()
res.Type, err = ParseParamType(typStr) res.Type, err = ParseParamType(typStr)
if err != nil { if err != nil {
return nil, err return nil, err
@ -422,6 +424,13 @@ func NewParameterFromString(in string) (*Parameter, error) {
if !hadType { if !hadType {
res.Type = inferParamType(val) res.Type = inferParamType(val)
} }
if res.Type == ByteArrayType && typStr == fileBytesParamType {
res.Value, err = ioutil.ReadFile(val)
if err != nil {
return nil, fmt.Errorf("failed to read '%s' parameter from file '%s': %w", fileBytesParamType, val, err)
}
return res, nil
}
res.Value, err = adjustValToType(res.Type, val) res.Value, err = adjustValToType(res.Type, val)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -481,6 +481,12 @@ func TestNewParameterFromString(t *testing.T) {
}, { }, {
in: `Map:[]`, in: `Map:[]`,
err: true, err: true,
}, {
in: "filebytes:./testdata/adjustValToType_filebytes_good.txt",
out: Parameter{Type: ByteArrayType, Value: []byte{0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x65, 0x66}},
}, {
in: "filebytes:./testdata/does_not_exists.txt",
err: true,
}} }}
for _, inout := range inouts { for _, inout := range inouts {
out, err := NewParameterFromString(inout.in) out, err := NewParameterFromString(inout.in)

View file

@ -0,0 +1 @@
010203ef