diff --git a/Makefile b/Makefile index e5c6f78408..75dcb2d7c2 100644 --- a/Makefile +++ b/Makefile @@ -327,7 +327,7 @@ endif fixture-stdlib: make stdlib - cp language/stdlib/staged/stdlib.mv ol/fixtures/stdlib/fresh_stdlib.mv + cp language/diem-framework/staged/stdlib.mv ol/fixtures/stdlib/fresh_stdlib.mv #### HELPERS #### check: diff --git a/language/diem-framework/modules/0L/Oracle.move b/language/diem-framework/modules/0L/Oracle.move index 5d5f888d04..0ff39418a4 100644 --- a/language/diem-framework/modules/0L/Oracle.move +++ b/language/diem-framework/modules/0L/Oracle.move @@ -339,11 +339,21 @@ address 0x1 { } public fun enable_delegation (sender: &signer) { - move_to(sender, VoteDelegation{ - vote_delegated: false, - delegates: Vector::empty
(), - delegated_to_address: Signer::address_of(sender), - }); + if (!exists(Signer::address_of(sender))) { + move_to(sender, VoteDelegation{ + vote_delegated: false, + delegates: Vector::empty
(), + delegated_to_address: Signer::address_of(sender), + }); + } + } + + public fun has_delegated (account: address): bool acquires VoteDelegation { + if (exists(account)) { + let del = borrow_global(account); + return del.vote_delegated + }; + false } public fun check_number_delegates (addr: address): u64 acquires VoteDelegation { @@ -354,6 +364,8 @@ address 0x1 { public fun delegate_vote (sender: &signer, vote_dest: address) acquires VoteDelegation{ assert(exists(Signer::address_of(sender)), Errors::not_published(DELEGATION_NOT_ENABLED)); + + // check if the receipient/destination has enabled delegation. assert(exists(vote_dest), Errors::not_published(DELEGATION_NOT_ENABLED)); let del = borrow_global_mut(Signer::address_of(sender)); diff --git a/language/diem-framework/modules/0L_transaction_scripts/ol_oracle.move b/language/diem-framework/modules/0L_transaction_scripts/ol_oracle.move index 167070e361..d53b345134 100644 --- a/language/diem-framework/modules/0L_transaction_scripts/ol_oracle.move +++ b/language/diem-framework/modules/0L_transaction_scripts/ol_oracle.move @@ -1,8 +1,29 @@ address 0x1 { module OracleScripts { use 0x1::Oracle; + public(script) fun ol_oracle_tx(sender: signer, id: u64, data: vector) { Oracle::handler(&sender, id, data); } + + /// A validator (Alice) can delegate the authority for the operation of an upgrade to another validator (Bob). When Oracle delegation happens, effectively the consensus voting power of Alice, is added to Bob only for the effect of calculating the preference on electing a stdlib binary. Whatever binary Bob proposes, Alice will also propose without needing to be submitting transactions. + + public(script) fun ol_delegate_vote(sender: signer, dest: address) { + // if for some reason not delegated + Oracle::enable_delegation(&sender); + + Oracle::delegate_vote(&sender, dest); + } + + /// First Bob must have delegation enabled, which can be done with: + + public(script) fun ol_enable_delegation(sender: signer) { + Oracle::enable_delegation(&sender); + } + /// Alice can remove Bob as the delegate with this function. + public(script) fun ol_remove_delegation(sender: signer) { + Oracle::remove_delegate_vote(&sender); + } + } } \ No newline at end of file diff --git a/language/diem-framework/modules/DiemAccount.move b/language/diem-framework/modules/DiemAccount.move index a6ba09a461..6b1deb5111 100644 --- a/language/diem-framework/modules/DiemAccount.move +++ b/language/diem-framework/modules/DiemAccount.move @@ -563,13 +563,15 @@ module DiemAccount { // User can join validator universe list, but will only join if // the mining is above the threshold in the preceeding period. - ValidatorUniverse::add_self(&new_signer); - + ValidatorUniverse::add_self(&new_signer); + make_account(new_signer, auth_key_prefix); make_account(new_op_account, op_auth_key_prefix); MinerState::reset_rate_limit(sender); + + // Transfer for owner onboarding_gas_transfer(sender, new_account_address); // Transfer for operator as well diff --git a/language/diem-framework/modules/doc/DiemAccount.md b/language/diem-framework/modules/doc/DiemAccount.md index 563998f8e3..64145d5139 100644 --- a/language/diem-framework/modules/doc/DiemAccount.md +++ b/language/diem-framework/modules/doc/DiemAccount.md @@ -1515,6 +1515,8 @@ Initialize this module. This is only callable from genesis. MinerState::reset_rate_limit(sender); + + // Transfer for owner onboarding_gas_transfer<GAS>(sender, new_account_address); // Transfer for operator as well diff --git a/language/diem-framework/modules/doc/Oracle.md b/language/diem-framework/modules/doc/Oracle.md index bd39bdf140..d954b52341 100644 --- a/language/diem-framework/modules/doc/Oracle.md +++ b/language/diem-framework/modules/doc/Oracle.md @@ -25,6 +25,7 @@ - [Function `get_threshold`](#0x1_Oracle_get_threshold) - [Function `calculate_proportional_voting_threshold`](#0x1_Oracle_calculate_proportional_voting_threshold) - [Function `enable_delegation`](#0x1_Oracle_enable_delegation) +- [Function `has_delegated`](#0x1_Oracle_has_delegated) - [Function `check_number_delegates`](#0x1_Oracle_check_number_delegates) - [Function `delegate_vote`](#0x1_Oracle_delegate_vote) - [Function `remove_delegate_vote`](#0x1_Oracle_remove_delegate_vote) @@ -890,11 +891,41 @@
public fun enable_delegation (sender: &signer) {
-  move_to<VoteDelegation>(sender, VoteDelegation{
-    vote_delegated: false,
-    delegates: Vector::empty<address>(),
-    delegated_to_address: Signer::address_of(sender),
-  });
+  if (!exists<VoteDelegation>(Signer::address_of(sender))) {
+    move_to<VoteDelegation>(sender, VoteDelegation{
+      vote_delegated: false,
+      delegates: Vector::empty<address>(),
+      delegated_to_address: Signer::address_of(sender),
+    });
+  }
+}
+
+ + + + + + + +## Function `has_delegated` + + + +
public fun has_delegated(account: address): bool
+
+ + + +
+Implementation + + +
public fun has_delegated (account: address): bool acquires VoteDelegation {
+  if (exists<VoteDelegation>(account)) {
+    let del = borrow_global<VoteDelegation>(account);
+    return del.vote_delegated
+  };
+  false
 }
 
@@ -945,6 +976,8 @@
public fun delegate_vote (sender: &signer, vote_dest: address) acquires VoteDelegation{
   assert(exists<VoteDelegation>(Signer::address_of(sender)), Errors::not_published(DELEGATION_NOT_ENABLED));
+
+  // check if the receipient/destination has enabled delegation.
   assert(exists<VoteDelegation>(vote_dest), Errors::not_published(DELEGATION_NOT_ENABLED));
 
   let del = borrow_global_mut<VoteDelegation>(Signer::address_of(sender));
diff --git a/language/diem-framework/modules/doc/ol_oracle.md b/language/diem-framework/modules/doc/ol_oracle.md
index bb378c9d15..ae7a5ae46b 100644
--- a/language/diem-framework/modules/doc/ol_oracle.md
+++ b/language/diem-framework/modules/doc/ol_oracle.md
@@ -6,6 +6,9 @@
 
 
 -  [Function `ol_oracle_tx`](#0x1_OracleScripts_ol_oracle_tx)
+-  [Function `ol_delegate_vote`](#0x1_OracleScripts_ol_delegate_vote)
+-  [Function `ol_enable_delegation`](#0x1_OracleScripts_ol_enable_delegation)
+-  [Function `ol_remove_delegation`](#0x1_OracleScripts_ol_remove_delegation)
 
 
 
use 0x1::Oracle;
@@ -35,6 +38,84 @@
 
 
 
+
+ + + +## Function `ol_delegate_vote` + +A validator (Alice) can delegate the authority for the operation of an upgrade to another validator (Bob). When Oracle delegation happens, effectively the consensus voting power of Alice, is added to Bob only for the effect of calculating the preference on electing a stdlib binary. Whatever binary Bob proposes, Alice will also propose without needing to be submitting transactions. + + +
public(script) fun ol_delegate_vote(sender: signer, dest: address)
+
+ + + +
+Implementation + + +
public(script) fun ol_delegate_vote(sender: signer, dest: address) {
+    // if for some reason not delegated
+    Oracle::enable_delegation(&sender);
+
+    Oracle::delegate_vote(&sender, dest);
+}
+
+ + + +
+ + + +## Function `ol_enable_delegation` + +First Bob must have delegation enabled, which can be done with: + + +
public(script) fun ol_enable_delegation(sender: signer)
+
+ + + +
+Implementation + + +
public(script) fun ol_enable_delegation(sender: signer) {
+    Oracle::enable_delegation(&sender);
+}
+
+ + + +
+ + + +## Function `ol_remove_delegation` + +Alice can remove Bob as the delegate with this function. + + +
public(script) fun ol_remove_delegation(sender: signer)
+
+ + + +
+Implementation + + +
public(script) fun ol_remove_delegation(sender: signer) {
+    Oracle::remove_delegate_vote(&sender);
+}
+
+ + +
diff --git a/language/diem-framework/releases/artifacts/current/docs/modules/DiemAccount.md b/language/diem-framework/releases/artifacts/current/docs/modules/DiemAccount.md index 563998f8e3..64145d5139 100644 --- a/language/diem-framework/releases/artifacts/current/docs/modules/DiemAccount.md +++ b/language/diem-framework/releases/artifacts/current/docs/modules/DiemAccount.md @@ -1515,6 +1515,8 @@ Initialize this module. This is only callable from genesis. MinerState::reset_rate_limit(sender); + + // Transfer for owner onboarding_gas_transfer<GAS>(sender, new_account_address); // Transfer for operator as well diff --git a/language/diem-framework/releases/artifacts/current/docs/modules/Oracle.md b/language/diem-framework/releases/artifacts/current/docs/modules/Oracle.md index bd39bdf140..d954b52341 100644 --- a/language/diem-framework/releases/artifacts/current/docs/modules/Oracle.md +++ b/language/diem-framework/releases/artifacts/current/docs/modules/Oracle.md @@ -25,6 +25,7 @@ - [Function `get_threshold`](#0x1_Oracle_get_threshold) - [Function `calculate_proportional_voting_threshold`](#0x1_Oracle_calculate_proportional_voting_threshold) - [Function `enable_delegation`](#0x1_Oracle_enable_delegation) +- [Function `has_delegated`](#0x1_Oracle_has_delegated) - [Function `check_number_delegates`](#0x1_Oracle_check_number_delegates) - [Function `delegate_vote`](#0x1_Oracle_delegate_vote) - [Function `remove_delegate_vote`](#0x1_Oracle_remove_delegate_vote) @@ -890,11 +891,41 @@
public fun enable_delegation (sender: &signer) {
-  move_to<VoteDelegation>(sender, VoteDelegation{
-    vote_delegated: false,
-    delegates: Vector::empty<address>(),
-    delegated_to_address: Signer::address_of(sender),
-  });
+  if (!exists<VoteDelegation>(Signer::address_of(sender))) {
+    move_to<VoteDelegation>(sender, VoteDelegation{
+      vote_delegated: false,
+      delegates: Vector::empty<address>(),
+      delegated_to_address: Signer::address_of(sender),
+    });
+  }
+}
+
+ + + + + + + +## Function `has_delegated` + + + +
public fun has_delegated(account: address): bool
+
+ + + +
+Implementation + + +
public fun has_delegated (account: address): bool acquires VoteDelegation {
+  if (exists<VoteDelegation>(account)) {
+    let del = borrow_global<VoteDelegation>(account);
+    return del.vote_delegated
+  };
+  false
 }
 
@@ -945,6 +976,8 @@
public fun delegate_vote (sender: &signer, vote_dest: address) acquires VoteDelegation{
   assert(exists<VoteDelegation>(Signer::address_of(sender)), Errors::not_published(DELEGATION_NOT_ENABLED));
+
+  // check if the receipient/destination has enabled delegation.
   assert(exists<VoteDelegation>(vote_dest), Errors::not_published(DELEGATION_NOT_ENABLED));
 
   let del = borrow_global_mut<VoteDelegation>(Signer::address_of(sender));
diff --git a/language/diem-framework/releases/artifacts/current/docs/modules/ol_oracle.md b/language/diem-framework/releases/artifacts/current/docs/modules/ol_oracle.md
index bb378c9d15..ae7a5ae46b 100644
--- a/language/diem-framework/releases/artifacts/current/docs/modules/ol_oracle.md
+++ b/language/diem-framework/releases/artifacts/current/docs/modules/ol_oracle.md
@@ -6,6 +6,9 @@
 
 
 -  [Function `ol_oracle_tx`](#0x1_OracleScripts_ol_oracle_tx)
+-  [Function `ol_delegate_vote`](#0x1_OracleScripts_ol_delegate_vote)
+-  [Function `ol_enable_delegation`](#0x1_OracleScripts_ol_enable_delegation)
+-  [Function `ol_remove_delegation`](#0x1_OracleScripts_ol_remove_delegation)
 
 
 
use 0x1::Oracle;
@@ -35,6 +38,84 @@
 
 
 
+
+ + + +## Function `ol_delegate_vote` + +A validator (Alice) can delegate the authority for the operation of an upgrade to another validator (Bob). When Oracle delegation happens, effectively the consensus voting power of Alice, is added to Bob only for the effect of calculating the preference on electing a stdlib binary. Whatever binary Bob proposes, Alice will also propose without needing to be submitting transactions. + + +
public(script) fun ol_delegate_vote(sender: signer, dest: address)
+
+ + + +
+Implementation + + +
public(script) fun ol_delegate_vote(sender: signer, dest: address) {
+    // if for some reason not delegated
+    Oracle::enable_delegation(&sender);
+
+    Oracle::delegate_vote(&sender, dest);
+}
+
+ + + +
+ + + +## Function `ol_enable_delegation` + +First Bob must have delegation enabled, which can be done with: + + +
public(script) fun ol_enable_delegation(sender: signer)
+
+ + + +
+Implementation + + +
public(script) fun ol_enable_delegation(sender: signer) {
+    Oracle::enable_delegation(&sender);
+}
+
+ + + +
+ + + +## Function `ol_remove_delegation` + +Alice can remove Bob as the delegate with this function. + + +
public(script) fun ol_remove_delegation(sender: signer)
+
+ + + +
+Implementation + + +
public(script) fun ol_remove_delegation(sender: signer) {
+    Oracle::remove_delegate_vote(&sender);
+}
+
+ + +
diff --git a/language/diem-framework/releases/artifacts/current/modules/067_Oracle.mv b/language/diem-framework/releases/artifacts/current/modules/067_Oracle.mv index 9b04d8a6bf..2693c05dce 100644 Binary files a/language/diem-framework/releases/artifacts/current/modules/067_Oracle.mv and b/language/diem-framework/releases/artifacts/current/modules/067_Oracle.mv differ diff --git a/language/diem-framework/releases/artifacts/current/modules/072_OracleScripts.mv b/language/diem-framework/releases/artifacts/current/modules/072_OracleScripts.mv index 12730e0897..d3a5ec4d0b 100644 Binary files a/language/diem-framework/releases/artifacts/current/modules/072_OracleScripts.mv and b/language/diem-framework/releases/artifacts/current/modules/072_OracleScripts.mv differ diff --git a/language/diem-framework/releases/artifacts/current/script_abis/ol_oracle/ol_delegate_vote.abi b/language/diem-framework/releases/artifacts/current/script_abis/ol_oracle/ol_delegate_vote.abi new file mode 100644 index 0000000000..aef18b97ac Binary files /dev/null and b/language/diem-framework/releases/artifacts/current/script_abis/ol_oracle/ol_delegate_vote.abi differ diff --git a/language/diem-framework/releases/artifacts/current/script_abis/ol_oracle/ol_enable_delegation.abi b/language/diem-framework/releases/artifacts/current/script_abis/ol_oracle/ol_enable_delegation.abi new file mode 100644 index 0000000000..d79065f9a0 Binary files /dev/null and b/language/diem-framework/releases/artifacts/current/script_abis/ol_oracle/ol_enable_delegation.abi differ diff --git a/language/diem-framework/releases/artifacts/current/script_abis/ol_oracle/ol_remove_delegation.abi b/language/diem-framework/releases/artifacts/current/script_abis/ol_oracle/ol_remove_delegation.abi new file mode 100644 index 0000000000..12945456eb Binary files /dev/null and b/language/diem-framework/releases/artifacts/current/script_abis/ol_oracle/ol_remove_delegation.abi differ diff --git a/language/diem-framework/releases/artifacts/current/transaction_script_builder.rs b/language/diem-framework/releases/artifacts/current/transaction_script_builder.rs index 232c0b3afe..59246f1595 100644 --- a/language/diem-framework/releases/artifacts/current/transaction_script_builder.rs +++ b/language/diem-framework/releases/artifacts/current/transaction_script_builder.rs @@ -2220,6 +2220,14 @@ pub enum ScriptFunctionCall { MinerstateHelper {}, + /// A validator (Alice) can delegate the authority for the operation of an upgrade to another validator (Bob). When Oracle delegation happens, effectively the consensus voting power of Alice, is added to Bob only for the effect of calculating the preference on electing a stdlib binary. Whatever binary Bob proposes, Alice will also propose without needing to be submitting transactions. + OlDelegateVote { + dest: AccountAddress, + }, + + /// First Bob must have delegation enabled, which can be done with: + OlEnableDelegation {}, + OlOracleTx { id: u64, data: Bytes, @@ -2233,6 +2241,9 @@ pub enum ScriptFunctionCall { ram: AccountAddress, }, + /// Alice can remove Bob as the delegate with this function. + OlRemoveDelegation {}, + /// # Summary /// Transfers a given number of coins in a specified currency from one account to another. /// Transfers over a specified amount defined on-chain that are between two different VASPs, or @@ -3611,6 +3622,8 @@ impl ScriptFunctionCall { solution, ), MinerstateHelper {} => encode_minerstate_helper_script_function(), + OlDelegateVote { dest } => encode_ol_delegate_vote_script_function(dest), + OlEnableDelegation {} => encode_ol_enable_delegation_script_function(), OlOracleTx { id, data } => encode_ol_oracle_tx_script_function(id, data), OlReconfigBulkUpdateSetup { alice, @@ -3619,6 +3632,7 @@ impl ScriptFunctionCall { sha, ram, } => encode_ol_reconfig_bulk_update_setup_script_function(alice, bob, carol, sha, ram), + OlRemoveDelegation {} => encode_ol_remove_delegation_script_function(), PeerToPeerWithMetadata { currency, payee, @@ -4923,6 +4937,32 @@ pub fn encode_minerstate_helper_script_function() -> TransactionPayload { )) } +/// A validator (Alice) can delegate the authority for the operation of an upgrade to another validator (Bob). When Oracle delegation happens, effectively the consensus voting power of Alice, is added to Bob only for the effect of calculating the preference on electing a stdlib binary. Whatever binary Bob proposes, Alice will also propose without needing to be submitting transactions. +pub fn encode_ol_delegate_vote_script_function(dest: AccountAddress) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]), + ident_str!("OracleScripts").to_owned(), + ), + ident_str!("ol_delegate_vote").to_owned(), + vec![], + vec![bcs::to_bytes(&dest).unwrap()], + )) +} + +/// First Bob must have delegation enabled, which can be done with: +pub fn encode_ol_enable_delegation_script_function() -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]), + ident_str!("OracleScripts").to_owned(), + ), + ident_str!("ol_enable_delegation").to_owned(), + vec![], + vec![], + )) +} + pub fn encode_ol_oracle_tx_script_function(id: u64, data: Vec) -> TransactionPayload { TransactionPayload::ScriptFunction(ScriptFunction::new( ModuleId::new( @@ -4959,6 +4999,19 @@ pub fn encode_ol_reconfig_bulk_update_setup_script_function( )) } +/// Alice can remove Bob as the delegate with this function. +pub fn encode_ol_remove_delegation_script_function() -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]), + ident_str!("OracleScripts").to_owned(), + ), + ident_str!("ol_remove_delegation").to_owned(), + vec![], + vec![], + )) +} + /// # Summary /// Transfers a given number of coins in a specified currency from one account to another. /// Transfers over a specified amount defined on-chain that are between two different VASPs, or @@ -8236,6 +8289,28 @@ fn decode_minerstate_helper_script_function( } } +fn decode_ol_delegate_vote_script_function( + payload: &TransactionPayload, +) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(ScriptFunctionCall::OlDelegateVote { + dest: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } +} + +fn decode_ol_enable_delegation_script_function( + payload: &TransactionPayload, +) -> Option { + if let TransactionPayload::ScriptFunction(_script) = payload { + Some(ScriptFunctionCall::OlEnableDelegation {}) + } else { + None + } +} + fn decode_ol_oracle_tx_script_function(payload: &TransactionPayload) -> Option { if let TransactionPayload::ScriptFunction(script) = payload { Some(ScriptFunctionCall::OlOracleTx { @@ -8263,6 +8338,16 @@ fn decode_ol_reconfig_bulk_update_setup_script_function( } } +fn decode_ol_remove_delegation_script_function( + payload: &TransactionPayload, +) -> Option { + if let TransactionPayload::ScriptFunction(_script) = payload { + Some(ScriptFunctionCall::OlRemoveDelegation {}) + } else { + None + } +} + fn decode_peer_to_peer_with_metadata_script_function( payload: &TransactionPayload, ) -> Option { @@ -9115,6 +9200,14 @@ static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy std::fmt::Result { - write!(f, "unable to parse AccoutAddress") + write!(f, "unable to parse AccountAddress") } } diff --git a/language/tools/vm-genesis/src/lib.rs b/language/tools/vm-genesis/src/lib.rs index 07fca12e99..628cf6b0b3 100644 --- a/language/tools/vm-genesis/src/lib.rs +++ b/language/tools/vm-genesis/src/lib.rs @@ -654,7 +654,7 @@ fn create_and_initialize_owners_operators( { let staged_owner_auth_key = AuthenticationKey::ed25519(owner_key.as_ref().unwrap()); let owner_address = staged_owner_auth_key.derived_address(); - // let owner_address = diem_config::utils::validator_owner_account_from_name(owner_name); + exec_function( session, log_context, @@ -667,19 +667,17 @@ fn create_and_initialize_owners_operators( ]), ); - // give the operator balance to be able to send txs for owner, e.g. tower-builder - // exec_function( - // session, - // log_context, - // "DiemAccount", - // "genesis_fund_operator", - // vec![], - // serialize_values(&vec![ - // MoveValue::Signer(diem_root_address), - // MoveValue::Signer(owner_address), - // MoveValue::Address(*operator_account), - // ]), - // ); + // enable oracle upgrade delegation for all genesis nodes. + exec_function( + session, + log_context, + "Oracle", + "enable_delegation", + vec![], + serialize_values(&vec![ + MoveValue::Signer(owner_address), + ]), + ); } } diff --git a/ol/documentation/ops/archived/stdlib_upgrade_payload.md b/ol/documentation/ops/archived/stdlib_upgrade_payload.md index 5b09d59bc1..a25e875d21 100644 --- a/ol/documentation/ops/archived/stdlib_upgrade_payload.md +++ b/ol/documentation/ops/archived/stdlib_upgrade_payload.md @@ -14,7 +14,7 @@ You need a newly compiled stdlib, otherwise you risk using stale code. `cargo run --release -p stdlib -- --create-upgrade-payload` -- this should write a stdlib file to `language/stdlib/staged/stdlib.mv` +- this should write a stdlib file to `language/diem-framework/staged/stdlib.mv` ## e2e Testing @@ -39,7 +39,7 @@ The important feature of this file is that it is essentially identical to the st 4. Copy concatenated file from `stdlib/staged/stdlib.mv`, to `fixtures/upgrade_payload/foo_stdlib.mv` -- `cp language/stdlib/staged/stdlib.mv fixtures/upgrade_payload/foo_stdlib.mv` +- `cp language/diem-framework/staged/stdlib.mv fixtures/upgrade_payload/foo_stdlib.mv` 5. Important, you must now *comment away* the foo() code again in Upgrade.move. 6. Rebuild stdlib again. Otherwise the e2e test will be starting from an stdlib which includes foo(), when it should not. diff --git a/ol/documentation/ops/archived/v4.3.0_upgrade.md b/ol/documentation/ops/archived/v4.3.0_upgrade.md index 7d3484623f..6abbf36482 100644 --- a/ol/documentation/ops/archived/v4.3.0_upgrade.md +++ b/ol/documentation/ops/archived/v4.3.0_upgrade.md @@ -59,7 +59,7 @@ NOTE: You will NOT build the binaries during Part 1, to prevent incompatibility # output Creating staged/stdlib.mv for upgrade oracle ... (took 1.624s) -sha256sum language/stdlib/staged/stdlib.mv +sha256sum language/diem-framework/staged/stdlib.mv 79a3878e7291194dcebf6afc134e62a011fadb8651e8647d653beb6f7c0710ff language/stdlib/staged/s tdlib.mv ``` @@ -86,7 +86,7 @@ The hash should equal: > cargo run --release -p stdlib -- --create-upgrade-payload # check hash -> sha256sum language/stdlib/staged/stdlib.mv +> sha256sum language/diem-framework/staged/stdlib.mv ``` ### Submit the upgrade transaction @@ -110,7 +110,7 @@ Location: txs/src/commands/oracle_upgrade_cmd.rs:21 The `txs` app is looking in 0L.toml for the path to the stdlib compile. -The toml has by default `stdlib_bin_path = "/root/libra/language/stdlib/staged/stdlib.mv"` which may differ on your machine. +The toml has by default `stdlib_bin_path = "/root/libra/language/diem-framework/staged/stdlib.mv"` which may differ on your machine. To resolve you can either: diff --git a/ol/documentation/ops/archived/v4.3.3_upgrade.md b/ol/documentation/ops/archived/v4.3.3_upgrade.md index 2005ee8eac..541b2da6f8 100644 --- a/ol/documentation/ops/archived/v4.3.3_upgrade.md +++ b/ol/documentation/ops/archived/v4.3.3_upgrade.md @@ -64,7 +64,7 @@ The step above also builds stdlib and created the upgrade bundle. You can check the hash with: ``` -sha256sum language/stdlib/staged/stdlib.mv +sha256sum language/diem-framework/staged/stdlib.mv ``` v4.3.3 hash is: `84c2f5e9527dcd1d4a635dd2103f7a4e98ed46451841fa84febf33c6c5cfe934` diff --git a/ol/documentation/ops/offline_app_configs.md b/ol/documentation/ops/offline_app_configs.md index 40d53e0af6..5cace01b4a 100644 --- a/ol/documentation/ops/offline_app_configs.md +++ b/ol/documentation/ops/offline_app_configs.md @@ -38,5 +38,5 @@ ol --config path/to/config/0L.toml explorer ### TXS ``` # submit upgrade tx -txs --config path/to/config/0L.toml oracle-upgrade -f path/to/libra/language/stdlib/staged/stdlib.mv +txs --config path/to/config/0L.toml oracle-upgrade -f path/to/libra/language/diem-framework/staged/stdlib.mv ``` \ No newline at end of file diff --git a/ol/documentation/ops/stdlib_hot_upgrade.md b/ol/documentation/ops/stdlib_hot_upgrade.md index e69de29bb2..88f40363d8 100644 --- a/ol/documentation/ops/stdlib_hot_upgrade.md +++ b/ol/documentation/ops/stdlib_hot_upgrade.md @@ -0,0 +1,100 @@ +## Summary +Hot upgrades to 0L Move framework (AKA "stdlib") require no halting of the network and are achieved with the Upgrade Oracle. This can be done when there are non-breaking changes to the vm (in Rust), and the stdlib (Move) has migrations in place in case of schema changes. + +## Voting on Upgrades +Validators vote on upgrades. They vote by either sending the full binary of the stdlib or the hash of an stdlib binary which has already been submitted. + +Proposals for upgrade expire after 1M blocks have elapsed. + +It takes a minimum of two epochs (48h) for an upgrade to take place. + +At the beginning of each epoch (specifically round 2), the VM checks if the quorum has been met (2/3 of validators by voting power) for an upgrade. Assuming there is quorum the upgrade does not take place immediately, instead there's a cooling off period of 1 epoch. The upgrade happens on the subsequent epoch. + + +## A First Proposal +If there is no stdlib binary yet proposed, any validator can submit one with these steps. You will need to have the source code. + +1. Checkout the tag of the release indended for upgrade of the `libra` repo. +2. Build the new stdlib using the Makefile helper `make stdlib`. +3. From a CLI issue the oracle upgrade command to vote on upgrade: + +When you compile the stdlib by default they go to: `<0L source>/language/diem-framework/staged/stdlib.mv`). You should pass the path explicitly with: + +``` +txs oracle-upgrade --vote -f +``` +Note: You may edit your 0L.toml file under `workspace` to include `stdlib_bin_path = "/root/libra/language/diem-framework/staged/stdlib.mv`. Then you don't need to pass the file path explicitly. This may become deprecated. +## Subsequent Proposals +Subsequent proposals can use the exact same step above. In that case the validator is verifying the compilation of stdlib when voting. That is the preferred method. + +The validator can also vote by simply sending the hash of the stdlib of a previously proposed binary. In that case it can be done with: + +`txs oracle-upgrade -v -h ` + +WARNING: this is lazy, and reduces the security of the network, but may be necessary at times given your local configuration. If you are lazy, that's ok, but you should instead "delegate" your upgrade authority to another validator. + +# Delegation + +A validator (Alice) can delegate the authority for the operation of an upgrade to another validator (Bob). When Oracle delegation happens, effectively the consensus voting power of Alice, is added to Bob only for the effect of calculating the preference on electing a stdlib binary. Whatever binary Bob proposes, Alice will also propose without needing to be submitting transactions. + +First Bob must have delegation enabled, which can be done with: + +``` +txs oracle-upgrade --enable-delegation + +``` + +Assigment of a delegate (by Alice), can be done with: + +``` +txs oracle-upgrade --delegate + +``` + +Alice can remove Bob as the delegate with this function. +``` +txs oracle-upgrade --remove-delegate + +``` + +### How do we know it's successful + +The `web-monitor` displays current upgrade proposals under the tab `upgrade`. + +Otherwise with the CLI: + +Using ol client, you can query the system address for the stucts OracleUpgrade +``` +cargo r -p ol -- -a 00000000000000000000000000000000 query --move-state --move-module Oracle --move-struct OracleUpgrade --move-value validators_voted +``` + +Or for the Upgrade state + +``` +cargo r -p ol -- -a 00000000000000000000000000000000 query --move-state --move-module Upgrade --move-struct UpgradeHistory --move-value records +``` + +It's also possible to query `diem-client` with `query ar 0x0` but this is a very noisy display. + +## Node Logs + +The upgrade happens on every "upgrade tick" (block 2 of the epoch) on the epoch following when 2/3 operators have reached consensus on upgrade. + +in the node logs you will see: + +``` +====================================== checking upgrade +====================================== consensus reached +====================================== published 59 modules +====================================== end publish module at + +``` + +## Trouble Shooting: +1. Server returned error: reqwest::Error { kind: Status(413), url: "http://localhost:8080/" } + +-- Ensure you updated ~/.0L/node.yaml file + +2. Transaction submission failed with error: JsonRpcError { code: -32001, message: "Server error: VM Validation error: INSUFFICIENT_BALANCE_FOR_TRANSACTION_FEE", data: Some(StatusCode(INSUFFICIENT_BALANCE_FOR_TRANSACTION_FEE)) } + +-- This is likely testnet and you don't have balance from mining. diff --git a/ol/documentation/stdlib_upgrade_payload_v5.md b/ol/documentation/stdlib_upgrade_payload_v5.md index b36080eb54..618d39b461 100644 --- a/ol/documentation/stdlib_upgrade_payload_v5.md +++ b/ol/documentation/stdlib_upgrade_payload_v5.md @@ -14,7 +14,7 @@ You need a newly compiled stdlib, otherwise you risk using stale code. `ol/util/create-upgrade-payload.sh` -- this should write a stdlib file to `language/stdlib/staged/stdlib.mv` +- this should write a stdlib file to `language/diem-framework/staged/stdlib.mv` ## e2e Testing diff --git a/ol/fixtures/configs/alice.toml b/ol/fixtures/configs/alice.toml index da748fbbe2..abed85c9b8 100644 --- a/ol/fixtures/configs/alice.toml +++ b/ol/fixtures/configs/alice.toml @@ -2,7 +2,7 @@ node_home = "/root/.0L/" source_path = "/root/libra" block_dir = "blocks" -stdlib_bin_path = "/root/libra/language/stdlib/staged/stdlib.mv" +stdlib_bin_path = "/root/libra/language/diem-framework/staged/stdlib.mv" db_path = "/root/.0L/db" [profile] diff --git a/ol/fixtures/configs/bob.toml b/ol/fixtures/configs/bob.toml index c984b9f3e1..9b5e41a19a 100644 --- a/ol/fixtures/configs/bob.toml +++ b/ol/fixtures/configs/bob.toml @@ -2,7 +2,7 @@ node_home = "/root/.0L/" source_path = "/root/libra" block_dir = "blocks" -stdlib_bin_path = "/root/libra/language/stdlib/staged/stdlib.mv" +stdlib_bin_path = "/root/libra/language/diem-framework/staged/stdlib.mv" db_path = "/root/.0L/db" [profile] diff --git a/ol/fixtures/configs/carol.toml b/ol/fixtures/configs/carol.toml index fb12af0d55..5a394512f9 100644 --- a/ol/fixtures/configs/carol.toml +++ b/ol/fixtures/configs/carol.toml @@ -2,7 +2,7 @@ node_home = "/root/.0L/" source_path = "/root/libra" block_dir = "blocks" -stdlib_bin_path = "/root/libra/language/stdlib/staged/stdlib.mv" +stdlib_bin_path = "/root/libra/language/diem-framework/staged/stdlib.mv" db_path = "/root/.0L/db" [profile] diff --git a/ol/fixtures/configs/dave.toml b/ol/fixtures/configs/dave.toml index 71d7bb89cc..f856f9e1dd 100644 --- a/ol/fixtures/configs/dave.toml +++ b/ol/fixtures/configs/dave.toml @@ -2,7 +2,7 @@ node_home = "/root/.0L/" source_path = "/root/libra" block_dir = "blocks" -stdlib_bin_path = "/root/libra/language/stdlib/staged/stdlib.mv" +stdlib_bin_path = "/root/libra/language/diem-framework/staged/stdlib.mv" db_path = "/root/.0L/db" [profile] diff --git a/ol/fixtures/configs/eve.toml b/ol/fixtures/configs/eve.toml index 8b62f3c3c8..beacbc7dd1 100644 --- a/ol/fixtures/configs/eve.toml +++ b/ol/fixtures/configs/eve.toml @@ -2,7 +2,7 @@ node_home = "/root/.0L/" source_path = "/root/libra" block_dir = "blocks" -stdlib_bin_path = "/root/libra/language/stdlib/staged/stdlib.mv" +stdlib_bin_path = "/root/libra/language/diem-framework/staged/stdlib.mv" db_path = "/root/.0L/db" [profile] diff --git a/ol/integration-tests/test-upgrade.mk b/ol/integration-tests/test-upgrade.mk index a2bfcab826..94748689be 100644 --- a/ol/integration-tests/test-upgrade.mk +++ b/ol/integration-tests/test-upgrade.mk @@ -75,11 +75,11 @@ init: cp ${SWARM_TEMP}/0/0L.toml ${HOME}/.0L/0L.toml submit: - cd ${SOURCE_PATH} && cargo run -p txs -- --swarm-path ${SWARM_TEMP} --swarm-persona ${PERSONA} oracle-upgrade -f ${STDLIB_BIN_HOLDING} + cd ${SOURCE_PATH} && cargo run -p txs -- --swarm-path ${SWARM_TEMP} --swarm-persona ${PERSONA} oracle-upgrade -v -f ${STDLIB_BIN_HOLDING} submit-hash: echo ${HASH} - cd ${SOURCE_PATH} && cargo run -p txs -- --swarm-path ${SWARM_TEMP} --swarm-persona ${PERSONA} oracle-upgrade-hash -h ${HASH} + cd ${SOURCE_PATH} && cargo run -p txs -- --swarm-path ${SWARM_TEMP} --swarm-persona ${PERSONA} oracle-upgrade -v -h ${HASH} query: cd ${SOURCE_PATH} && cargo run -p ol -- --swarm-path ${SWARM_TEMP} --swarm-persona ${PERSONA} query --blockheight | grep -Eo [0-9]+ | tail -n1 diff --git a/ol/txs/src/commands.rs b/ol/txs/src/commands.rs index d7687d498c..c78f043fc0 100644 --- a/ol/txs/src/commands.rs +++ b/ol/txs/src/commands.rs @@ -30,7 +30,6 @@ use self::{ create_account_cmd::CreateAccountCmd, create_validator_cmd::CreateValidatorCmd, oracle_upgrade_cmd::OracleUpgradeCmd, - oracle_upgrade_cmd::OracleUpgradeHashCmd, version_cmd::VersionCmd, autopay_batch_cmd::AutopayBatchCmd, autopay_cmd::AutopayCmd, @@ -56,10 +55,6 @@ pub enum TxsCmd { /// The `oracle-upgrade` subcommand #[options(help = "submit an oracle transaction to upgrade stdlib")] OracleUpgrade(OracleUpgradeCmd), - - /// The `oracle-upgrade-hash` subcommand - #[options(help = "submit an oracle transaction to upgrade stdlib")] - OracleUpgradeHash(OracleUpgradeHashCmd), /// The `autopay` subcommand #[options(help = "enable or disable autopay")] diff --git a/ol/txs/src/commands/oracle_upgrade_cmd.rs b/ol/txs/src/commands/oracle_upgrade_cmd.rs index 41a5af966f..2f2078e807 100644 --- a/ol/txs/src/commands/oracle_upgrade_cmd.rs +++ b/ol/txs/src/commands/oracle_upgrade_cmd.rs @@ -5,55 +5,75 @@ use abscissa_core::{Command, Options, Runnable}; use ol_types::config::TxType; use crate::{entrypoint, prelude::app_config, submit_tx::{tx_params_wrapper, maybe_submit}}; -use diem_types::transaction::TransactionPayload; +use diem_types::{account_address::AccountAddress, transaction::TransactionPayload}; use diem_transaction_builder::stdlib as transaction_builder; use std::{fs, io::prelude::*, path::PathBuf, process::exit}; /// `OracleUpgrade` subcommand #[derive(Command, Debug, Default, Options)] pub struct OracleUpgradeCmd { + #[options(short = "v", help = "Do the vote tx")] + vote: bool, #[options(short = "f", help = "Path of upgrade file")] upgrade_file_path: Option, + #[options(short = "h", help = "Use hash instead of binary")] + hash: Option, + #[options(short = "d", help = "Delegate voting power to another validator")] + delegate: Option, + #[options(short = "e", help = "Enable delegation")] + enable_delegation: bool, + #[options(short = "r", help = "Remove delegation")] + remove_delegation: bool, } -pub fn oracle_tx_script(upgrade_file_path: &PathBuf) -> TransactionPayload { - let mut file = fs::File::open(upgrade_file_path) - .expect("file should open read only"); - let mut buffer = Vec::new(); - file.read_to_end(&mut buffer).expect("failed to read the file"); - - let id = 1; // upgrade is oracle #1 - transaction_builder::encode_ol_oracle_tx_script_function(id, buffer) -} impl Runnable for OracleUpgradeCmd { fn run(&self) { let entry_args = entrypoint::get_args(); let tx_params = tx_params_wrapper(TxType::Critical).unwrap(); + + let script = if self.vote { - let path = self.upgrade_file_path.clone().unwrap_or_else(|| { - let cfg = app_config(); - match cfg.workspace.stdlib_bin_path.clone() { - Some(p) => p, - None => { - println!( - "could not find path to compiled stdlib.mv, was this set in 0L.toml? \ - Alternatively pass the full path with: \ - -f /language/stdlib/staged/stdlib.mv" - ); - exit(1); - }, + if let Some(hex_hash) = &self.hash { + let bytes = hex::decode(hex_hash).expect("Input must be a hex string"); + oracle_hash_tx_script(bytes) + } else { + let path = self.upgrade_file_path.clone().unwrap_or_else(|| { + let cfg = app_config(); + match cfg.workspace.stdlib_bin_path.clone() { + Some(p) => p, + None => { + println!( + "could not find path to compiled stdlib.mv, was this set in 0L.toml? \ + Alternatively pass the full path with: \ + -f /language/diem-framework/staged/stdlib.mv" + ); + exit(1); + }, + } + }); + + oracle_tx_script(&path) } - }); - + } else if self.enable_delegation { + transaction_builder::encode_ol_enable_delegation_script_function() + } else if self.remove_delegation { + transaction_builder::encode_ol_remove_delegation_script_function() + } else if let Some(destination) = self.delegate { + transaction_builder::encode_ol_delegate_vote_script_function(destination) + } else { + println!("Nothing to do from command line args. Did you mean to pass --vote?"); + exit(1); + }; + match maybe_submit( - oracle_tx_script(&path), + script, &tx_params, entry_args.no_send, entry_args.save_path ) { Err(e) => { - println!("ERROR: could not submit upgrade transaction, message: \n{:?}", &e); + println!("ERROR: could not submit oracle transaction, message: \n{:?}", &e); exit(1); }, _ => {} @@ -61,31 +81,19 @@ impl Runnable for OracleUpgradeCmd { } } -/// `OracleUpgradeHash` subcommand -#[derive(Command, Debug, Default, Options)] -pub struct OracleUpgradeHashCmd { - #[options(short = "h", help = "Upgrade hash")] - upgrade_hash: String, + + +pub fn oracle_tx_script(upgrade_file_path: &PathBuf) -> TransactionPayload { + let mut file = fs::File::open(upgrade_file_path) + .expect("file should open read only"); + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer).expect("failed to read the file"); + + let id = 1; // upgrade is oracle #1 + transaction_builder::encode_ol_oracle_tx_script_function(id, buffer) } pub fn oracle_hash_tx_script(upgrade_hash: Vec) -> TransactionPayload { let id = 2; // upgrade with hash is oracle #2 transaction_builder::encode_ol_oracle_tx_script_function(id, upgrade_hash) } - -impl Runnable for OracleUpgradeHashCmd { - fn run(&self) { - let entry_args = entrypoint::get_args(); - let tx_params = tx_params_wrapper(TxType::Critical).unwrap(); - - let hash = self.upgrade_hash.clone(); - let hex_hash = hex::decode(hash).expect("Input must be a hex string"); - - maybe_submit( - oracle_hash_tx_script(hex_hash), - &tx_params, - entry_args.no_send, - entry_args.save_path - ).unwrap(); - } -} diff --git a/ol/types/src/config.rs b/ol/types/src/config.rs index 51cdbc5e87..df5d865fc2 100644 --- a/ol/types/src/config.rs +++ b/ol/types/src/config.rs @@ -163,7 +163,7 @@ impl AppCfg { // let source_path = what_source(); default_config.workspace.source_path = source_path.clone(); default_config.workspace.stdlib_bin_path = Some( - source_path.as_ref().unwrap().join("language/stdlib/staged/stdlib.mv") + source_path.as_ref().unwrap().join("language/diem-framework/staged/stdlib.mv") ); } @@ -332,7 +332,7 @@ pub struct Workspace { #[serde(default = "default_db_path")] pub db_path: PathBuf, /// Path to which stdlib binaries for upgrades get built typically - /// /language/stdlib/staged/stdlib.mv + /// /language/diem-framework/staged/stdlib.mv pub stdlib_bin_path: Option, } diff --git a/ol/util/test-upgrade.mk b/ol/util/test-upgrade.mk index ad0b928e3a..5edde8018b 100644 --- a/ol/util/test-upgrade.mk +++ b/ol/util/test-upgrade.mk @@ -59,14 +59,14 @@ get-test: stdlib: cd ${SOURCE_PATH} && cargo run --release -p stdlib cd ${SOURCE_PATH} && cargo run --release -p stdlib -- --create-upgrade-payload - sha256sum ${SOURCE_PATH}/language/stdlib/staged/stdlib.mv + sha256sum ${SOURCE_PATH}/language/diem-framework/staged/stdlib.mv init: cd ${SOURCE_PATH} && cargo run -p ol -- --swarm-path ${SWARM_TEMP} --swarm-persona ${PERSONA} init cp ${SWARM_TEMP}/0/0L.toml ${HOME}/.0L/0L.toml submit: - cd ${SOURCE_PATH} && cargo run -p txs -- --swarm-path ${SWARM_TEMP} --swarm-persona ${PERSONA} oracle-upgrade -f ${SOURCE_PATH}/language/stdlib/staged/stdlib.mv + cd ${SOURCE_PATH} && cargo run -p txs -- --swarm-path ${SWARM_TEMP} --swarm-persona ${PERSONA} oracle-upgrade -f ${SOURCE_PATH}/language/diem-framework/staged/stdlib.mv query: cd ${SOURCE_PATH} && cargo run -p ol -- --swarm-path ${SWARM_TEMP} --swarm-persona ${PERSONA} query --blockheight | grep -Eo [0-9]+ | tail -n1