Skip to content

Commit

Permalink
fix: dashevo cmd (#10)
Browse files Browse the repository at this point in the history
* refactor: add an implementation of specific unmarshalers for quorum subtype
* fix: update TestDashEvoCmds
  • Loading branch information
shotonoff authored Mar 2, 2022
1 parent b417ad8 commit f525d5b
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 16 deletions.
38 changes: 37 additions & 1 deletion btcjson/cmdparse.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,19 @@ func UnmarshalCmd(r *Request) (interface{}, error) {
return nil, err
}

cmd := rvp.Interface()
unmarshaler, ok := cmd.(Unmarshaler)
if ok {
// unmarshal every parameter item from json.RawMessage into a go type value
// result of this operation will be a slice of the interfaces
args, err := unmarshalArgItems(r.Params)
if err != nil {
return nil, err
}
err = unmarshaler.UnmarshalArgs(args)
return unmarshaler, err
}

// Loop through each of the struct fields and unmarshal the associated
// parameter into them.
for i := 0; i < numParams; i++ {
Expand Down Expand Up @@ -555,6 +568,13 @@ func NewCmd(method string, args ...interface{}) (interface{}, error) {
rv := rvp.Elem()
rt := rtp.Elem()

cmd := rvp.Interface()
unmarshaler, ok := cmd.(Unmarshaler)
if ok {
err := unmarshaler.UnmarshalArgs(args)
return unmarshaler, err
}

// Loop through each of the struct fields and assign the associated
// parameter into them after checking its type validity.
for i := 0; i < numParams; i++ {
Expand All @@ -568,5 +588,21 @@ func NewCmd(method string, args ...interface{}) (interface{}, error) {
}
}

return rvp.Interface(), nil
return cmd, nil
}

// Unmarshaler is an interface for a specific unmarshal function of arguments
type Unmarshaler interface {
UnmarshalArgs(args []interface{}) error
}

func unmarshalArgItems(params []json.RawMessage) ([]interface{}, error) {
args := make([]interface{}, len(params))
for i, val := range params {
err := json.Unmarshal(val, &args[i])
if err != nil {
return nil, err
}
}
return args, nil
}
110 changes: 104 additions & 6 deletions btcjson/dashevocmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@

package btcjson

import "errors"

func init() {
// No special flags for commands in this file.
flags := UsageFlag(0)

MustRegisterCmd("quorum", (*QuorumCmd)(nil), flags)
MustRegisterCmd("bls", (*BLSCmd)(nil), flags)
MustRegisterCmd("protx", (*ProTxCmd)(nil), flags)
}

type BLSSubCmd string

const (
Expand Down Expand Up @@ -117,6 +128,11 @@ const (
LLMQType_5_60 LLMQType = 100 //24 blocks
)

var (
errWrongSizeOfArgs = errors.New("wrong size of arguments")
errQuorumUnmarshalerNotFound = errors.New("quorum unmarshaler not found")
)

// QuorumCmd defines the quorum JSON-RPC command.
type QuorumCmd struct {
SubCmd QuorumCmdSubCmd `jsonrpcusage:"\"list|info|dkgstatus|sign|getrecsig|hasrecsig|isconflicting|memberof|selectquorum\""`
Expand Down Expand Up @@ -422,11 +438,93 @@ func NewProTxRevokeCmd(proTxHash, operatorPrivateKey string, reason int, feeSour
return r
}

func init() {
// No special flags for commands in this file.
flags := UsageFlag(0)
// UnmarshalArgs maps a list of arguments to quorum struct
func (q *QuorumCmd) UnmarshalArgs(args []interface{}) error {
if len(args) == 0 {
return errWrongSizeOfArgs
}
subCmd := args[0].(string)
q.SubCmd = QuorumCmdSubCmd(subCmd)
unmarshaler, ok := quorumCmdUnmarshalers[string(q.SubCmd)]
if !ok {
return errQuorumUnmarshalerNotFound
}
return unmarshaler(q, args[1:])
}

MustRegisterCmd("quorum", (*QuorumCmd)(nil), flags)
MustRegisterCmd("bls", (*BLSCmd)(nil), flags)
MustRegisterCmd("protx", (*ProTxCmd)(nil), flags)
type unmarshalQuorumCmdFunc func(*QuorumCmd, []interface{}) error

var quorumCmdUnmarshalers = map[string]unmarshalQuorumCmdFunc{
"info": withQuorumUnmarshaler(quorumInfoUnmarshaler, validateQuorumArgs(3), unmarshalQuorumLLMQType),
"sign": withQuorumUnmarshaler(quorumSignUnmarshaler, validateQuorumArgs(5), unmarshalQuorumLLMQType),
"verify": withQuorumUnmarshaler(quorumVerifyUnmarshaler, validateQuorumArgs(5), unmarshalQuorumLLMQType),
}

func unmarshalLLMQType(val interface{}) (LLMQType, error) {
var vInt int
switch tv := val.(type) {
case float64:
vInt = int(tv)
case float32:
vInt = int(tv)
case int:
vInt = tv
case LLMQType:
return tv, nil
}
return LLMQType(vInt), nil
}

func quorumInfoUnmarshaler(q *QuorumCmd, args []interface{}) error {
q.QuorumHash = strPtr(args[1].(string))
q.IncludeSkShare = boolPtr(args[2].(bool))
return nil
}

func quorumSignUnmarshaler(q *QuorumCmd, args []interface{}) error {
q.RequestID = strPtr(args[1].(string))
q.MessageHash = strPtr(args[2].(string))
q.QuorumHash = strPtr(args[3].(string))
q.Submit = boolPtr(args[4].(bool))
return nil
}

func unmarshalQuorumLLMQType(next unmarshalQuorumCmdFunc) unmarshalQuorumCmdFunc {
return func(q *QuorumCmd, args []interface{}) error {
val, err := unmarshalLLMQType(args[0])
if err != nil {
return err
}
q.LLMQType = llmqTypePtr(val)
return next(q, args)
}
}

func quorumVerifyUnmarshaler(q *QuorumCmd, args []interface{}) error {
q.RequestID = strPtr(args[1].(string))
q.MessageHash = strPtr(args[2].(string))
q.QuorumHash = strPtr(args[3].(string))
q.Signature = strPtr(args[4].(string))
return nil
}

func validateQuorumArgs(n int) func(unmarshalQuorumCmdFunc) unmarshalQuorumCmdFunc {
return func(next unmarshalQuorumCmdFunc) unmarshalQuorumCmdFunc {
return func(q *QuorumCmd, args []interface{}) error {
if n > len(args) {
return errWrongSizeOfArgs
}
return next(q, args)
}
}
}

func withQuorumUnmarshaler(
unmarshaler unmarshalQuorumCmdFunc,
fns ...func(unmarshalQuorumCmdFunc) unmarshalQuorumCmdFunc,
) unmarshalQuorumCmdFunc {
for _, fn := range fns {
unmarshaler = fn(unmarshaler)
}
return unmarshaler
}
22 changes: 13 additions & 9 deletions btcjson/dashevocmds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func pLLMQType(l btcjson.LLMQType) *btcjson.LLMQType { return &l }
func TestDashEvoCmds(t *testing.T) {
t.Parallel()

testID := int(1)
testID := 1
tests := []struct {
name string
newCmd func() (interface{}, error)
Expand All @@ -37,7 +37,7 @@ func TestDashEvoCmds(t *testing.T) {
{
name: "quorum sign",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("quorum sign", btcjson.LLMQType_100_67,
return btcjson.NewCmd("quorum", "sign", btcjson.LLMQType_100_67,
"0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1",
"ce490ca26cad6f1749ff9b977fe0fe4ece4391166f69be75c4619bc94b184dbc",
"6f1018f54507606069303fd16257434073c6f374729b0090bb9dbbe629241236",
Expand All @@ -50,8 +50,9 @@ func TestDashEvoCmds(t *testing.T) {
"6f1018f54507606069303fd16257434073c6f374729b0090bb9dbbe629241236",
false)
},
marshalled: `{"jsonrpc":"1.0","method":"quorum sign","params":[4,"0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1","ce490ca26cad6f1749ff9b977fe0fe4ece4391166f69be75c4619bc94b184dbc","6f1018f54507606069303fd16257434073c6f374729b0090bb9dbbe629241236",false],"id":1}`,
marshalled: `{"jsonrpc":"1.0","method":"quorum","params":["sign",4,"0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1","ce490ca26cad6f1749ff9b977fe0fe4ece4391166f69be75c4619bc94b184dbc","6f1018f54507606069303fd16257434073c6f374729b0090bb9dbbe629241236",false],"id":1}`,
unmarshalled: &btcjson.QuorumCmd{
SubCmd: "sign",
LLMQType: pLLMQType(btcjson.LLMQType_100_67),
RequestID: pString("0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1"),
MessageHash: pString("ce490ca26cad6f1749ff9b977fe0fe4ece4391166f69be75c4619bc94b184dbc"),
Expand All @@ -62,7 +63,7 @@ func TestDashEvoCmds(t *testing.T) {
{
name: "quorum info",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("quorum info", btcjson.LLMQType_100_67,
return btcjson.NewCmd("quorum", "info", btcjson.LLMQType_100_67,
"0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1",
false)
},
Expand All @@ -71,22 +72,24 @@ func TestDashEvoCmds(t *testing.T) {
"0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1",
false)
},
marshalled: `{"jsonrpc":"1.0","method":"quorum info","params":[4,"0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1",false],"id":1}`,
marshalled: `{"jsonrpc":"1.0","method":"quorum","params":["info",4,"0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1",false],"id":1}`,
unmarshalled: &btcjson.QuorumCmd{
SubCmd: "info",
LLMQType: pLLMQType(btcjson.LLMQType_100_67),
QuorumHash: pString("0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1"),
IncludeSkShare: pBool(false),
},
},
{
name: "quorum verify",
name: "quorum",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("quorum verify",
return btcjson.NewCmd("quorum",
"verify",
btcjson.LLMQType_100_67,
"0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1",
"ce490ca26cad6f1749ff9b977fe0fe4ece4391166f69be75c4619bc94b184dbc",
"6f1018f54507606069303fd16257434073c6f374729b0090bb9dbbe629241236",
false)
"5f1018f54507606069303fd16257434073c6f374729b0090bb9dbbe629241235")
},
staticCmd: func() interface{} {
return btcjson.NewQuorumVerifyCmd(btcjson.LLMQType_100_67,
Expand All @@ -95,8 +98,9 @@ func TestDashEvoCmds(t *testing.T) {
"5f1018f54507606069303fd16257434073c6f374729b0090bb9dbbe629241235",
"6f1018f54507606069303fd16257434073c6f374729b0090bb9dbbe629241236")
},
marshalled: `{"jsonrpc":"1.0","method":"quorum sign","params":[4,"0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1","ce490ca26cad6f1749ff9b977fe0fe4ece4391166f69be75c4619bc94b184dbc","5f1018f54507606069303fd16257434073c6f374729b0090bb9dbbe629241235","6f1018f54507606069303fd16257434073c6f374729b0090bb9dbbe629241236",],"id":1}`,
marshalled: `{"jsonrpc":"1.0","method":"quorum","params":["verify",4,"0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1","ce490ca26cad6f1749ff9b977fe0fe4ece4391166f69be75c4619bc94b184dbc","6f1018f54507606069303fd16257434073c6f374729b0090bb9dbbe629241236","5f1018f54507606069303fd16257434073c6f374729b0090bb9dbbe629241235"],"id":1}`,
unmarshalled: &btcjson.QuorumCmd{
SubCmd: "verify",
LLMQType: pLLMQType(btcjson.LLMQType_100_67),
RequestID: pString("0067c4fd779a195a95b267e263c631f71f83f8d5e6191091289d114012b373a1"),
MessageHash: pString("ce490ca26cad6f1749ff9b977fe0fe4ece4391166f69be75c4619bc94b184dbc"),
Expand Down
13 changes: 13 additions & 0 deletions btcjson/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package btcjson

func strPtr(v string) *string {
return &v
}

func boolPtr(v bool) *bool {
return &v
}

func llmqTypePtr(v LLMQType) *LLMQType {
return &v
}

0 comments on commit f525d5b

Please sign in to comment.