Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Construction End Conditions #122

Merged
merged 7 commits into from
Sep 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ check-format:
! gofmt -s -l . | read;

validate-configuration-files:
go run main.go configuration:validate examples/configuration/bitcoin.json;
go run main.go configuration:validate examples/configuration/ethereum.json;
go run main.go configuration:validate examples/configuration/simple.json;
go run main.go configuration:create examples/configuration/default.json;
Expand Down
46 changes: 28 additions & 18 deletions cmd/check_construction.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,14 @@ package cmd

import (
"context"
"fmt"
"log"
"os"
"time"

"github.com/coinbase/rosetta-cli/pkg/tester"

"github.com/coinbase/rosetta-sdk-go/fetcher"
"github.com/coinbase/rosetta-sdk-go/utils"
"github.com/fatih/color"
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
)
Expand Down Expand Up @@ -70,12 +69,24 @@ func runCheckConstructionCmd(cmd *cobra.Command, args []string) {

_, _, fetchErr := fetcher.InitializeAsserter(ctx)
if fetchErr != nil {
log.Fatalf("%s: unable to initialize asserter", fetchErr.Err.Error())
tester.ExitConstruction(
Config,
nil,
nil,
fmt.Errorf("%w: unable to initialize asserter", fetchErr.Err),
1,
)
}

_, err := utils.CheckNetworkSupported(ctx, Config.Network, fetcher)
if err != nil {
log.Fatalf("%s: unable to confirm network is supported", err.Error())
tester.ExitConstruction(
Config,
nil,
nil,
fmt.Errorf("%w: unable to confirm network is supported", err),
1,
)
}

constructionTester, err := tester.InitializeConstruction(
Expand All @@ -84,9 +95,16 @@ func runCheckConstructionCmd(cmd *cobra.Command, args []string) {
Config.Network,
fetcher,
cancel,
&SignalReceived,
)
if err != nil {
log.Fatalf("%s: unable to initialize construction tester", err.Error())
tester.ExitConstruction(
Config,
nil,
nil,
fmt.Errorf("%w: unable to initialize construction tester", err),
1,
)
}

defer constructionTester.CloseDatabase(ctx)
Expand All @@ -108,21 +126,13 @@ func runCheckConstructionCmd(cmd *cobra.Command, args []string) {
return constructionTester.StartConstructor(ctx)
})

g.Go(func() error {
return constructionTester.WatchEndConditions(ctx)
})

sigListeners := []context.CancelFunc{cancel}
go handleSignals(sigListeners)

err = g.Wait()
if SignalReceived {
color.Red("Check halted")
os.Exit(1)
return
}

if err != nil {
color.Red("Check failed: %s", err.Error())
os.Exit(1)
}

// Will only hit this once exit conditions are added
color.Green("Check succeeded")
constructionTester.HandleErr(err)
}
4 changes: 2 additions & 2 deletions cmd/check_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func runCheckDataCmd(cmd *cobra.Command, args []string) {

_, _, fetchErr := fetcher.InitializeAsserter(ctx)
if fetchErr != nil {
tester.Exit(
tester.ExitData(
Config,
nil,
nil,
Expand All @@ -95,7 +95,7 @@ func runCheckDataCmd(cmd *cobra.Command, args []string) {

networkStatus, err := utils.CheckNetworkSupported(ctx, Config.Network, fetcher)
if err != nil {
tester.Exit(
tester.ExitData(
Config,
nil,
nil,
Expand Down
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,6 @@ var versionCmd = &cobra.Command{
Use: "version",
Short: "Print rosetta-cli version",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("v0.4.2")
fmt.Println("v0.5.0")
},
}
17 changes: 12 additions & 5 deletions configuration/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,6 @@ var (
}
)

// TODO: Add support for sophisticated end conditions
// (https://github.com/coinbase/rosetta-cli/issues/66)

// ConstructionConfiguration contains all configurations
// to run check:construction.
type ConstructionConfiguration struct {
Expand Down Expand Up @@ -119,12 +116,23 @@ type ConstructionConfiguration struct {

// PrefundedAccounts is an array of prefunded accounts
// to use while testing.
PrefundedAccounts []*storage.PrefundedAccount `json:"prefunded_accounts"`
PrefundedAccounts []*storage.PrefundedAccount `json:"prefunded_accounts,omitempty"`

// Workflows are executed by the rosetta-cli to test
// certain construction flows. Make sure to define a
// "request_funds" and "create_account" workflow.
Workflows []*job.Workflow `json:"workflows"`

// EndConditions is a map of workflow:count that
// indicates how many of each workflow should be performed
// before check:construction should stop. For example,
// {"create_account": 5} indicates that 5 "create_account"
// workflows should be performed before stopping.
EndConditions map[string]int `json:"end_conditions,omitempty"`

// ResultsOutputFile is the absolute filepath of where to save
// the results of a check:construction run.
ResultsOutputFile string `json:"results_output_file,omitempty"`
}

// DefaultDataConfiguration returns the default *DataConfiguration
Expand Down Expand Up @@ -155,7 +163,6 @@ func DefaultConfiguration() *Configuration {

// DataEndConditions contains all the conditions for the syncer to stop
// when running check:data.
// Only 1 end condition can be populated at once!
type DataEndConditions struct {
// Index configures the syncer to stop once reaching a particular block height.
Index *int64 `json:"index,omitempty"`
Expand Down
212 changes: 212 additions & 0 deletions examples/configuration/bitcoin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
{
"network": {
"blockchain": "Bitcoin",
"network": "Testnet3"
},
"online_url": "",
"data_directory": "bitcoin-data",
"http_timeout": 300,
"retry_elapsed_time": 0,
"sync_concurrency": 0,
"transaction_concurrency": 0,
"tip_delay": 1800,
"disable_memory_limit": false,
"log_configuration": false,
"construction": {
"offline_url": "",
"stale_depth": 0,
"broadcast_limit": 0,
"ignore_broadcast_failures": false,
"clear_broadcasts": false,
"broadcast_behind_tip": false,
"block_broadcast_limit": 0,
"rebroadcast_all": false,
"workflows": [
{
"name": "request_funds",
"concurrency": 1,
"scenarios": [
{
"name": "find_address",
"actions": [
{
"input": "{\"symbol\":\"tBTC\", \"decimals\":8}",
"type": "set_variable",
"output_path": "currency"
},
{
"input": "{\"minimum_balance\":{\"value\": \"0\", \"currency\": {{currency}}}, \"create_limit\":1}",
"type": "find_balance",
"output_path": "random_address"
}
]
},
{
"name": "request",
"actions": [
{
"input": "{\"address\": {{random_address.account.address}}, \"minimum_balance\":{\"value\": \"1000000\", \"currency\": {{currency}}}}",
"type": "find_balance",
"output_path": "loaded_address"
}
]
}
]
},
{
"name": "create_account",
"concurrency": 1,
"scenarios": [
{
"name": "create_account",
"actions": [
{
"input": "{\"network\":\"Testnet3\", \"blockchain\":\"Bitcoin\"}",
"type": "set_variable",
"output_path": "network"
},
{
"input": "{\"curve_type\": \"secp256k1\"}",
"type": "generate_key",
"output_path": "key"
},
{
"input": "{\"network_identifier\": {{network}}, \"public_key\": {{key.public_key}}}",
"type": "derive",
"output_path": "address"
},
{
"input": "{\"address\": {{address.address}}, \"keypair\": {{key}}}",
"type": "save_address"
}
]
}
]
},
{
"name": "transfer",
"concurrency": 10,
"scenarios": [
{
"name": "transfer",
"actions": [
{
"input": "{\"network\":\"Testnet3\", \"blockchain\":\"Bitcoin\"}",
"type": "set_variable",
"output_path": "transfer.network"
},
{
"input": "{\"symbol\":\"tBTC\", \"decimals\":8}",
"type": "set_variable",
"output_path": "currency"
},
{
"input": "\"600\"",
"type": "set_variable",
"output_path": "dust_amount"
},
{
"input": "\"600\"",
"type": "set_variable",
"output_path": "fee_amount"
},
{
"input": "{\"operation\":\"addition\", \"left_value\": {{dust_amount}}, \"right_value\": {{fee_amount}}}",
"type": "math",
"output_path": "send_buffer"
},
{
"input": "\"1800\"",
"type": "set_variable",
"output_path": "reserved_amount"
},
{
"input": "{\"require_coin\":true, \"minimum_balance\":{\"value\": {{reserved_amount}}, \"currency\": {{currency}}}}",
"type": "find_balance",
"output_path": "sender"
},
{
"input": "{\"operation\":\"subtraction\", \"left_value\": {{sender.balance.value}}, \"right_value\": {{send_buffer}}}",
"type": "math",
"output_path": "available_amount"
},
{
"input": "{\"minimum\": {{dust_amount}}, \"maximum\": {{available_amount}}}",
"type": "random_number",
"output_path": "recipient_amount"
},
{
"input": "{\"recipient_amount\":{{recipient_amount}}}",
"type": "print_message"
},
{
"input": "{\"operation\":\"subtraction\", \"left_value\": {{sender.balance.value}}, \"right_value\": {{recipient_amount}}}",
"type": "math",
"output_path": "change_amount"
},
{
"input": "{\"operation\":\"subtraction\", \"left_value\": {{change_amount}}, \"right_value\": {{fee_amount}}}",
"type": "math",
"output_path": "change_amount"
},
{
"input": "{\"change_amount\":{{change_amount}}}",
"type": "print_message"
},
{
"input": "{\"operation\":\"subtraction\", \"left_value\": \"0\", \"right_value\":{{sender.balance.value}}}",
"type": "math",
"output_path": "sender_amount"
},
{
"input": "{\"not_address\":[{{sender.account.address}}], \"not_coins\":[{{sender.coin}}], \"minimum_balance\":{\"value\": \"0\", \"currency\": {{currency}}}, \"create_limit\": 100, \"create_probability\": 50}",
"type": "find_balance",
"output_path": "recipient"
},
{
"input": "\"1\"",
"type": "set_variable",
"output_path": "transfer.confirmation_depth"
},
{
"input": "[{\"operation_identifier\":{\"index\":0},\"type\":\"INPUT\",\"account\":{\"address\":{{sender.account.address}}},\"amount\":{\"value\":{{sender_amount}},\"currency\":{{currency}}}, \"coin_change\":{\"coin_action\":\"coin_spent\", \"coin_identifier\":{{sender.coin}}}},{\"operation_identifier\":{\"index\":1},\"type\":\"OUTPUT\",\"account\":{\"address\":{{recipient.account.address}}},\"amount\":{\"value\":{{recipient_amount}},\"currency\":{{currency}}}}, {\"operation_identifier\":{\"index\":2},\"type\":\"OUTPUT\",\"account\":{\"address\":{{sender.account.address}}},\"amount\":{\"value\":{{change_amount}},\"currency\":{{currency}}}}]",
"type": "set_variable",
"output_path": "transfer.operations"
},
{
"input": "{{transfer.operations}}",
"type": "print_message"
}
]
}
]
}
],
"end_conditions": {
"create_account": 10,
"transfer": 10
}
},
"data": {
"active_reconciliation_concurrency": 0,
"inactive_reconciliation_concurrency": 0,
"inactive_reconciliation_frequency": 0,
"log_blocks": false,
"log_transactions": false,
"log_balance_changes": false,
"log_reconciliations": false,
"ignore_reconciliation_error": false,
"exempt_accounts": "",
"bootstrap_balances": "",
"historical_balance_disabled": true,
"interesting_accounts": "",
"reconciliation_disabled": false,
"inactive_discrepency_search_disabled": false,
"balance_tracking_disabled": false,
"coin_tracking_disabled": false,
"end_conditions": {
"reconciliation_coverage": 0.95
},
"results_output_file": ""
}
}
Loading