diff --git a/.github/workflows/ansible-lint.yml b/.github/workflows/ansible-lint.yml new file mode 100644 index 0000000..3f4aff2 --- /dev/null +++ b/.github/workflows/ansible-lint.yml @@ -0,0 +1,24 @@ +name: Ansible Lint +on: + - pull_request + - push + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Lint Ansible playbooks + # Lastest commit, as of 30 Apr 2020 + uses: ansible/ansible-lint-action@6c8c141 + with: + targets: | + scripts/ansible/kill_playbook.yml + scripts/ansible/ping_playbook.yml + scripts/ansible/restart_playbook.yml + scripts/ansible/update_playbook.yml + + args: + -c scripts/ansible/.ansible-lint diff --git a/main/params.go b/main/params.go index 48444a7..a216720 100644 --- a/main/params.go +++ b/main/params.go @@ -24,10 +24,12 @@ import ( "github.com/ava-labs/gecko/utils/hashing" "github.com/ava-labs/gecko/utils/logging" "github.com/ava-labs/gecko/utils/wrappers" + "github.com/mitchellh/go-homedir" ) const ( - dbVersion = "v0.2.0" + dbVersion = "v0.2.0" + defaultDbDir = "~/.gecko/db" ) // Results of parsing the CLI @@ -80,7 +82,7 @@ func init() { // Database: db := fs.Bool("db-enabled", true, "Turn on persistent storage") - dbDir := fs.String("db-dir", "db", "Database directory for Ava state") + dbDir := fs.String("db-dir", defaultDbDir, "Database directory for Ava state") // IP: consensusIP := fs.String("public-ip", "", "Public IP of this node") @@ -147,6 +149,11 @@ func init() { // DB: if *db && err == nil { // TODO: Add better params here + if *dbDir == defaultDbDir { + if *dbDir, err = homedir.Expand(defaultDbDir); err != nil { + errs.Add(fmt.Errorf("couldn't resolve default db path: %v", err)) + } + } dbPath := path.Join(*dbDir, genesis.NetworkName(Config.NetworkID), dbVersion) db, err := leveldb.New(dbPath, 0, 0, 0) Config.DB = db diff --git a/networking/handshake_handlers.go b/networking/handshake_handlers.go index b605935..eeb94cf 100644 --- a/networking/handshake_handlers.go +++ b/networking/handshake_handlers.go @@ -69,7 +69,7 @@ var ( VersionSeparator = "." MajorVersion = 0 MinorVersion = 2 - PatchVersion = 0 + PatchVersion = 1 ClientVersion = fmt.Sprintf("%s%d%s%d%s%d", VersionPrefix, MajorVersion, diff --git a/scripts/ansible/.ansible-lint b/scripts/ansible/.ansible-lint new file mode 100644 index 0000000..a9514ea --- /dev/null +++ b/scripts/ansible/.ansible-lint @@ -0,0 +1,7 @@ +parsable: true +skip_list: + - '301' # Commands should not change things if nothing needs doing + - '204' # Lines should be no longer than 160 chars + - '502' # All tasks should be named + +# vim: filetype=yaml diff --git a/scripts/ansible/kill_playbook.yml b/scripts/ansible/kill_playbook.yml index 6e91645..03f9231 100755 --- a/scripts/ansible/kill_playbook.yml +++ b/scripts/ansible/kill_playbook.yml @@ -4,6 +4,5 @@ connection: ssh gather_facts: false hosts: all - tasks: - - name: Kill Node - command: killall ava \ No newline at end of file + roles: + - name: ava-stop diff --git a/scripts/ansible/ping_playbook.yml b/scripts/ansible/ping_playbook.yml index 0c47625..ffd7697 100755 --- a/scripts/ansible/ping_playbook.yml +++ b/scripts/ansible/ping_playbook.yml @@ -6,6 +6,4 @@ hosts: all tasks: - name: Ping node - shell: "ls" - environment: - PATH: /sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/snap/bin + ping: diff --git a/scripts/ansible/restart_playbook.yml b/scripts/ansible/restart_playbook.yml index 93b0bad..ee43d0e 100755 --- a/scripts/ansible/restart_playbook.yml +++ b/scripts/ansible/restart_playbook.yml @@ -9,30 +9,8 @@ repo_folder: ~/go/src/github.com/ava-labs/gecko repo_name: ava-labs/gecko-internal repo_branch: platformvm-proposal-accept - tasks: - - name: Kill Node - command: killall ava - ignore_errors: yes - - git: - repo: ssh://git@github.com/{{ repo_name }}.git - dest: "{{ repo_folder }}" - version: "{{ repo_branch }}" - update: yes - - name: Build project - command: ./scripts/build.sh - args: - chdir: "{{ repo_folder }}" - environment: - PATH: /sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/snap/bin - - name: Remove previous database - file: - path: "{{ db_dir }}" - state: absent - - name: Remove previous logs - file: - path: "{{ log_dir }}" - state: absent - - name: Start node - shell: "nohup {{ ava_binary }} --network-id={{ network_id }} --api-admin-enabled={{ api_admin_enabled }} --api-keystore-enabled={{ api_keystore_enabled }} --api-metrics-enabled={{ api_metrics_enabled }} --ava-tx-fee={{ ava_tx_fee }} --assertions-enabled={{ assertions_enabled }} --signature-verification-enabled={{ signature_verification_enabled }} --db-enabled={{ db_enabled }} --db-dir={{ db_dir }} --http-port={{ http_port }} --http-tls-enabled={{ http_tls_enabled }} --http-tls-key-file={{ http_tls_key_file }} --http-tls-cert-file={{ http_tls_cert_file }} --bootstrap-ips={{ bootstrap_ips }} --bootstrap-ids={{ bootstrap_ids }} --public-ip={{ ansible_host }} --staking-port={{ staking_port }} --staking-tls-enabled={{ staking_tls_enabled }} --staking-tls-key-file={{ staking_tls_key_file }} --staking-tls-cert-file={{ staking_tls_cert_file }} --plugin-dir={{ plugin_dir }} --log-dir={{ log_dir }} --log-level={{ log_level }} --snow-sample-size={{ snow_sample_size }} --snow-quorum-size={{ snow_quorum_size }} --snow-virtuous-commit-threshold={{ snow_virtuous_commit_threshold }} --snow-rogue-commit-threshold={{ snow_rogue_commit_threshold }} --snow-avalanche-num-parents={{ snow_avalanche_num_parents }} --snow-avalanche-batch-size={{ snow_avalanche_batch_size }} --api-ipcs-enabled={{ api_ipcs_enabled }} --xput-server-enabled={{ xput_server_enabled }} --xput-server-port={{ xput_server_port }} >/dev/null 2>&1 &" - environment: - PATH: /sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/snap/bin + roles: + - name: ava-stop + - name: ava-build + - name: ava-reset + - name: ava-start diff --git a/scripts/ansible/roles/ava-build/tasks/main.yml b/scripts/ansible/roles/ava-build/tasks/main.yml new file mode 100644 index 0000000..d059cda --- /dev/null +++ b/scripts/ansible/roles/ava-build/tasks/main.yml @@ -0,0 +1,13 @@ +- name: Update git clone + git: + repo: ssh://git@github.com/{{ repo_name }}.git + dest: "{{ repo_folder }}" + version: "{{ repo_branch }}" + update: yes + +- name: Build project + command: ./scripts/build.sh + args: + chdir: "{{ repo_folder }}" + environment: + PATH: /sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/snap/bin diff --git a/scripts/ansible/roles/ava-reset/tasks/main.yml b/scripts/ansible/roles/ava-reset/tasks/main.yml new file mode 100644 index 0000000..e2e9bda --- /dev/null +++ b/scripts/ansible/roles/ava-reset/tasks/main.yml @@ -0,0 +1,9 @@ +- name: Remove previous database + file: + path: "{{ db_dir }}" + state: absent + +- name: Remove previous logs + file: + path: "{{ log_dir }}" + state: absent diff --git a/scripts/ansible/roles/ava-start/tasks/main.yml b/scripts/ansible/roles/ava-start/tasks/main.yml new file mode 100644 index 0000000..fc7f277 --- /dev/null +++ b/scripts/ansible/roles/ava-start/tasks/main.yml @@ -0,0 +1,38 @@ +- name: Start node + shell: + nohup {{ ava_binary }} + --network-id="{{ network_id }}" + --api-admin-enabled="{{ api_admin_enabled }}" + --api-keystore-enabled="{{ api_keystore_enabled }}" + --api-metrics-enabled="{{ api_metrics_enabled }}" + --ava-tx-fee="{{ ava_tx_fee }}" + --assertions-enabled="{{ assertions_enabled }}" + --signature-verification-enabled="{{ signature_verification_enabled }}" + --db-enabled="{{ db_enabled }}" + --db-dir="{{ db_dir }}" + --http-port="{{ http_port }}" + --http-tls-enabled="{{ http_tls_enabled }}" + --http-tls-key-file="{{ http_tls_key_file }}" + --http-tls-cert-file="{{ http_tls_cert_file }}" + --bootstrap-ips="{{ bootstrap_ips }}" + --bootstrap-ids="{{ bootstrap_ids }}" + --public-ip="{{ ansible_host }}" + --staking-port="{{ staking_port }}" + --staking-tls-enabled="{{ staking_tls_enabled }}" + --staking-tls-key-file="{{ staking_tls_key_file }}" + --staking-tls-cert-file="{{ staking_tls_cert_file }}" + --plugin-dir="{{ plugin_dir }}" + --log-dir="{{ log_dir }}" + --log-level="{{ log_level }}" + --snow-sample-size="{{ snow_sample_size }}" + --snow-quorum-size="{{ snow_quorum_size }}" + --snow-virtuous-commit-threshold="{{ snow_virtuous_commit_threshold }}" + --snow-rogue-commit-threshold="{{ snow_rogue_commit_threshold }}" + --snow-avalanche-num-parents="{{ snow_avalanche_num_parents }}" + --snow-avalanche-batch-size="{{ snow_avalanche_batch_size }}" + --api-ipcs-enabled="{{ api_ipcs_enabled }}" + --xput-server-enabled="{{ xput_server_enabled }}" + --xput-server-port="{{ xput_server_port }}" + >/dev/null 2>&1 & + environment: + PATH: /sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/snap/bin diff --git a/scripts/ansible/roles/ava-stop/tasks/main.yml b/scripts/ansible/roles/ava-stop/tasks/main.yml new file mode 100644 index 0000000..1053cf0 --- /dev/null +++ b/scripts/ansible/roles/ava-stop/tasks/main.yml @@ -0,0 +1,3 @@ +- name: Kill Node + command: killall ava + ignore_errors: true diff --git a/scripts/ansible/update_playbook.yml b/scripts/ansible/update_playbook.yml index c31cf89..b704eee 100755 --- a/scripts/ansible/update_playbook.yml +++ b/scripts/ansible/update_playbook.yml @@ -9,22 +9,7 @@ repo_folder: ~/go/src/github.com/ava-labs/gecko repo_name: ava-labs/gecko-internal repo_branch: platformvm-proposal-accept - tasks: - - name: Kill Node - command: killall ava - ignore_errors: yes - - git: - repo: ssh://git@github.com/{{ repo_name }}.git - dest: "{{ repo_folder }}" - version: "{{ repo_branch }}" - update: yes - - name: Build project - command: ./scripts/build.sh - args: - chdir: "{{ repo_folder }}" - environment: - PATH: /sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/snap/bin - - name: Start node - shell: "nohup {{ ava_binary }} --network-id={{ network_id }} --api-admin-enabled={{ api_admin_enabled }} --api-keystore-enabled={{ api_keystore_enabled }} --api-metrics-enabled={{ api_metrics_enabled }} --ava-tx-fee={{ ava_tx_fee }} --assertions-enabled={{ assertions_enabled }} --signature-verification-enabled={{ signature_verification_enabled }} --db-enabled={{ db_enabled }} --db-dir={{ db_dir }} --http-port={{ http_port }} --http-tls-enabled={{ http_tls_enabled }} --http-tls-key-file={{ http_tls_key_file }} --http-tls-cert-file={{ http_tls_cert_file }} --bootstrap-ips={{ bootstrap_ips }} --bootstrap-ids={{ bootstrap_ids }} --public-ip={{ ansible_host }} --staking-port={{ staking_port }} --staking-tls-enabled={{ staking_tls_enabled }} --staking-tls-key-file={{ staking_tls_key_file }} --staking-tls-cert-file={{ staking_tls_cert_file }} --plugin-dir={{ plugin_dir }} --log-dir={{ log_dir }} --log-level={{ log_level }} --snow-sample-size={{ snow_sample_size }} --snow-quorum-size={{ snow_quorum_size }} --snow-virtuous-commit-threshold={{ snow_virtuous_commit_threshold }} --snow-rogue-commit-threshold={{ snow_rogue_commit_threshold }} --snow-avalanche-num-parents={{ snow_avalanche_num_parents }} --snow-avalanche-batch-size={{ snow_avalanche_batch_size }} --api-ipcs-enabled={{ api_ipcs_enabled }} --xput-server-enabled={{ xput_server_enabled }} --xput-server-port={{ xput_server_port }} >/dev/null 2>&1 &" - environment: - PATH: /sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/snap/bin + roles: + - name: ava-stop + - name: ava-build + - name: ava-start diff --git a/vms/platformvm/abort_block.go b/vms/platformvm/abort_block.go index 168fc2d..c0affde 100644 --- a/vms/platformvm/abort_block.go +++ b/vms/platformvm/abort_block.go @@ -20,13 +20,14 @@ type Abort struct { // // This function also sets onAcceptDB database if the verification passes. func (a *Abort) Verify() error { + parent, ok := a.parentBlock().(*ProposalBlock) // Abort is a decision, so its parent must be a proposal - if parent, ok := a.parentBlock().(*ProposalBlock); ok { - a.onAcceptDB, a.onAcceptFunc = parent.onAbort() - } else { + if !ok { return errInvalidBlockType } + a.onAcceptDB, a.onAcceptFunc = parent.onAbort() + a.vm.currentBlocks[a.ID().Key()] = a a.parentBlock().addChild(a) return nil diff --git a/vms/platformvm/commit_block.go b/vms/platformvm/commit_block.go index 00f746f..f619953 100644 --- a/vms/platformvm/commit_block.go +++ b/vms/platformvm/commit_block.go @@ -21,12 +21,13 @@ type Commit struct { // This function also sets the onCommit databases if the verification passes. func (c *Commit) Verify() error { // the parent of an Commit block should always be a proposal - if parent, ok := c.parentBlock().(*ProposalBlock); ok { - c.onAcceptDB, c.onAcceptFunc = parent.onCommit() - } else { + parent, ok := c.parentBlock().(*ProposalBlock) + if !ok { return errInvalidBlockType } + c.onAcceptDB, c.onAcceptFunc = parent.onCommit() + c.vm.currentBlocks[c.ID().Key()] = c c.parentBlock().addChild(c) return nil diff --git a/vms/platformvm/common_blocks.go b/vms/platformvm/common_blocks.go index a50dd2a..75ca97c 100644 --- a/vms/platformvm/common_blocks.go +++ b/vms/platformvm/common_blocks.go @@ -124,10 +124,6 @@ type CommonBlock struct { *core.Block `serialize:"true"` vm *VM - // This block's parent. - // nil before parentBlock() is called on this block - parent Block - // This block's children children []Block } @@ -142,7 +138,6 @@ func (cb *CommonBlock) Reject() { // free removes this block from memory func (cb *CommonBlock) free() { delete(cb.vm.currentBlocks, cb.ID().Key()) - cb.parent = nil cb.children = nil } @@ -165,11 +160,6 @@ func (cb *CommonBlock) Parent() snowman.Block { // parentBlock returns this block's parent func (cb *CommonBlock) parentBlock() Block { - // Check if the block already has a reference to its parent - if cb.parent != nil { - return cb.parent - } - // Get the parent from database parentID := cb.ParentID() parent, err := cb.vm.getBlock(parentID) @@ -177,7 +167,6 @@ func (cb *CommonBlock) parentBlock() Block { cb.vm.Ctx.Log.Debug("could not get parent (ID %s) of block %s", parentID, cb.ID()) return nil } - cb.parent = parent return parent.(Block) } diff --git a/vms/platformvm/proposal_block.go b/vms/platformvm/proposal_block.go index ac62303..7d70286 100644 --- a/vms/platformvm/proposal_block.go +++ b/vms/platformvm/proposal_block.go @@ -92,16 +92,17 @@ func (pb *ProposalBlock) onAbort() (*versiondb.Database, func()) { // // If this block is valid, this function also sets pas.onCommit and pas.onAbort. func (pb *ProposalBlock) Verify() error { - // pdb is the database if this block's parent is accepted - var pdb database.Database - parent := pb.parentBlock() + parentIntf := pb.parentBlock() + // The parent of a proposal block (ie this block) must be a decision block - if parent, ok := parent.(decision); ok { - pdb = parent.onAccept() - } else { + parent, ok := parentIntf.(decision) + if !ok { return errInvalidBlockType } + // pdb is the database if this block's parent is accepted + pdb := parent.onAccept() + var err error pb.onCommitDB, pb.onAbortDB, pb.onCommitFunc, pb.onAbortFunc, err = pb.Tx.SemanticVerify(pdb) if err != nil { @@ -109,7 +110,7 @@ func (pb *ProposalBlock) Verify() error { } pb.vm.currentBlocks[pb.ID().Key()] = pb - parent.addChild(pb) + parentIntf.addChild(pb) return nil } diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index e30dd8a..28be3fc 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -1596,3 +1596,81 @@ func TestBootstrapPartiallyAccepted(t *testing.T) { router.Shutdown() } + +func TestUnverifiedParent(t *testing.T) { + genesisAccounts := GenesisAccounts() + genesisValidators := GenesisCurrentValidators() + genesisChains := make([]*CreateChainTx, 0) + + genesisState := Genesis{ + Accounts: genesisAccounts, + Validators: genesisValidators, + Chains: genesisChains, + Timestamp: uint64(defaultGenesisTime.Unix()), + } + + genesisBytes, err := Codec.Marshal(genesisState) + if err != nil { + t.Fatal(err) + } + + db := memdb.New() + + vm := &VM{ + SnowmanVM: &core.SnowmanVM{}, + chainManager: chains.MockManager{}, + } + + defaultSubnet := validators.NewSet() + vm.validators = validators.NewManager() + vm.validators.PutValidatorSet(DefaultSubnetID, defaultSubnet) + + vm.clock.Set(defaultGenesisTime) + ctx := defaultContext() + msgChan := make(chan common.Message, 1) + if err := vm.Initialize(ctx, db, genesisBytes, msgChan, nil); err != nil { + t.Fatal(err) + } + + firstAdvanceTimeTx, err := vm.newAdvanceTimeTx(defaultGenesisTime.Add(time.Second)) + if err != nil { + t.Fatal(err) + } + firstAdvanceTimeBlk, err := vm.newProposalBlock(vm.Preferred(), firstAdvanceTimeTx) + if err != nil { + t.Fatal(err) + } + + vm.clock.Set(defaultGenesisTime.Add(2 * time.Second)) + if err := firstAdvanceTimeBlk.Verify(); err != nil { + t.Fatal(err) + } + + options := firstAdvanceTimeBlk.Options() + firstOption := options[0] + secondOption := options[1] + + secondAdvanceTimeTx, err := vm.newAdvanceTimeTx(defaultGenesisTime.Add(2 * time.Second)) + if err != nil { + t.Fatal(err) + } + secondAdvanceTimeBlk, err := vm.newProposalBlock(firstOption.ID(), secondAdvanceTimeTx) + if err != nil { + t.Fatal(err) + } + + parentBlk := secondAdvanceTimeBlk.Parent() + if parentBlkID := parentBlk.ID(); !parentBlkID.Equals(firstOption.ID()) { + t.Fatalf("Wrong parent block ID returned") + } + + if err := firstOption.Verify(); err != nil { + t.Fatal(err) + } + if err := secondOption.Verify(); err != nil { + t.Fatal(err) + } + if err := secondAdvanceTimeBlk.Verify(); err != nil { + t.Fatal(err) + } +}