diff --git a/btcjson/dashevocmds.go b/btcjson/dashevocmds.go index 698a974e44..159aeb7924 100644 --- a/btcjson/dashevocmds.go +++ b/btcjson/dashevocmds.go @@ -7,7 +7,10 @@ package btcjson -import "errors" +import ( + "errors" + "fmt" +) func init() { // No special flags for commands in this file. @@ -119,20 +122,73 @@ const ( type LLMQType int // Enum of LLMQTypes -// https://github.com/dashpay/dips/blob/master/dip-0006.md#current-llmq-types +// See https://github.com/dashpay/dips/blob/master/dip-0006.md#current-llmq-types and +// https://github.com/dashpay/dash/blob/master/src/llmq/params.h const ( - LLMQType_50_60 LLMQType = 1 //every 24 blocks - LLMQType_400_60 LLMQType = 2 //288 blocks - LLMQType_400_85 LLMQType = 3 //576 blocks - LLMQType_100_67 LLMQType = 4 //every 24 blocks - LLMQType_5_60 LLMQType = 100 //24 blocks + LLMQType_50_60 LLMQType = 1 // 50 members, 30 (60%) threshold, one per hour + LLMQType_400_60 LLMQType = 2 // 400 members, 240 (60%) threshold, one every 12 hours + LLMQType_400_85 LLMQType = 3 // 400 members, 340 (85%) threshold, one every 24 hours + LLMQType_100_67 LLMQType = 4 // 100 members, 67 (67%) threshold, one per hour + LLMQType_60_75 LLMQType = 5 // 60 members, 45 (75%) threshold, one every 12 hours + LLMQType_TEST LLMQType = 100 // 3 members, 2 (66%) threshold, one per hour + LLMQType_DEVNET LLMQType = 101 // 12 members, 6 (50%) threshold, one per hour + LLMQType_TEST_V17 LLMQType = 102 // 3 members, 2 (66%) threshold, one per hour + LLMQType_TEST_DIP0024 LLMQType = 103 // 4 members, 2 (66%) threshold, one per hour + LLMQType_TEST_INSTANTSEND LLMQType = 104 // 3 members, 2 (66%) threshold, one per hour + LLMQType_DEVNET_DIP0024 LLMQType = 105 // 8 members, 4 (50%) threshold, one per hour + + // LLMQType_5_60 is replaced with LLMQType_TEST to adhere to DIP-0006 naming + LLMQType_5_60 LLMQType = LLMQType_TEST ) var ( errWrongSizeOfArgs = errors.New("wrong size of arguments") errQuorumUnmarshalerNotFound = errors.New("quorum unmarshaler not found") + + llmqTypes map[string]LLMQType = map[string]LLMQType{ + "llmq_50_60": LLMQType_50_60, + "llmq_400_60": LLMQType_400_60, + "llmq_400_85": LLMQType_400_85, + "llmq_100_67": LLMQType_100_67, + "llmq_60_75": LLMQType_60_75, + "llmq_test": LLMQType_TEST, + "llmq_devnet": LLMQType_DEVNET, + "llmq_test_v17": LLMQType_TEST_V17, + "llmq_test_dip0024": LLMQType_TEST_DIP0024, + "llmq_test_instantsend": LLMQType_TEST_INSTANTSEND, + "llmq_devnet_dip0024": LLMQType_DEVNET_DIP0024, + } ) +// GetLLMQType returns LLMQ type for the given name. +// Returns 0 when the name is not supported. +func GetLLMQType(name string) LLMQType { + return llmqTypes[name] +} + +// Name returns name of the LLMQType. +// Returns empty string when the type is invalid. +// See https://github.com/dashpay/dash/blob/master/src/llmq/params.h +func (t LLMQType) Name() string { + for name, item := range llmqTypes { + if t == item { + return name + } + } + return "" +} + +// Validate checks if provided LLMQ type is valid, eg. if it's one of LLMQ types +// defined in accordance with DIP-0006. +// See https://github.com/dashpay/dips/blob/master/dip-0006/llmq-types.md +func (t LLMQType) Validate() error { + if (t >= LLMQType_50_60 && t <= LLMQType_60_75) || (t >= LLMQType_TEST && t <= LLMQType_DEVNET_DIP0024) { + return nil + } + + return fmt.Errorf("unsupported quorum type %d", t) +} + // QuorumCmd defines the quorum JSON-RPC command. type QuorumCmd struct { SubCmd QuorumCmdSubCmd `jsonrpcusage:"\"list|info|dkgstatus|sign|getrecsig|hasrecsig|isconflicting|memberof|selectquorum\""` diff --git a/btcjson/dashevocmds_test.go b/btcjson/dashevocmds_test.go index 370525459a..cf872ae569 100644 --- a/btcjson/dashevocmds_test.go +++ b/btcjson/dashevocmds_test.go @@ -10,6 +10,7 @@ import ( "encoding/json" "fmt" "reflect" + "strconv" "testing" "github.com/dashevo/dashd-go/btcjson" @@ -177,3 +178,46 @@ func TestDashEvoCmds(t *testing.T) { } } } + +func TestLLMQTypeValidate(t *testing.T) { + testCases := []struct { + llmqType btcjson.LLMQType + expectErr bool + }{{-1, true}, {0, true}, {1, false}, {2, false}, {5, false}, {6, true}, {99, true}, {100, false}, {105, false}, {106, true}} + + for _, tc := range testCases { + t.Run(strconv.Itoa(int(tc.llmqType)), func(t *testing.T) { + err := tc.llmqType.Validate() + if (err != nil) != tc.expectErr { + t.Errorf("LLMQ Type %d, expected error %v, got %s", tc.llmqType, tc.expectErr, err) + } + }) + } + +} + +func TestLLMQTypeString(t *testing.T) { + testCases := []struct { + llmqType btcjson.LLMQType + name string + }{ + {0, ""}, + {btcjson.LLMQType_400_60, "llmq_400_60"}, + {btcjson.LLMQType_TEST, "llmq_test"}, + {btcjson.LLMQType_5_60, "llmq_test"}, // exception + {999999, ""}, + } + for _, tc := range testCases { + t.Run(strconv.Itoa(int(tc.llmqType)), func(t *testing.T) { + gotName := tc.llmqType.Name() + if gotName != tc.name { + t.Errorf("invalid llmq type name, got: %s, expected: %s", tc.llmqType.Name(), tc.name) + } + + gotType := btcjson.GetLLMQType(tc.name) + if (gotName != "" && tc.llmqType != gotType) || (gotName == "" && gotType != 0) { + t.Errorf("invalid llmq type, got: %d, expected: %d", gotType, tc.llmqType) + } + }) + } +} diff --git a/rpcclient/evo_test.go b/rpcclient/evo_test.go index 57813d0ad1..1a52c5d33b 100644 --- a/rpcclient/evo_test.go +++ b/rpcclient/evo_test.go @@ -215,14 +215,6 @@ func TestQuorumMemberOf(t *testing.T) { compareWithCliCommand(t, &result, &cli, "quorum", "memberof", proTxHash) } -var llmqTypes = map[string]btcjson.LLMQType{ - "llmq_50_60": btcjson.LLMQType_50_60, - "llmq_400_60": btcjson.LLMQType_400_60, - "llmq_400_85": btcjson.LLMQType_400_85, - "llmq_100_67": btcjson.LLMQType_100_67, - "llmq_5_60": btcjson.LLMQType_5_60, -} - func TestQuorumSign(t *testing.T) { requestID := "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234" messageHash := "51c11d287dfa85aef3eebb5420834c8e443e01d15c0b0a8e397d67e2e51aa239" @@ -258,8 +250,8 @@ func TestQuorumSign(t *testing.T) { t.Fatal("not a member of any quorums") } quorumHash := mo[0].QuorumHash - quorumType, ok := llmqTypes[mo[0].Type] - if !ok { + quorumType := btcjson.GetLLMQType(mo[0].Type) + if quorumType == 0 { t.Fatal("unknown quorum type", mo[0].Type) }