Skip to content

Commit

Permalink
[cli] background tx submission service (#325)
Browse files Browse the repository at this point in the history
Co-authored-by: 0o-de-lally <[email protected]>
  • Loading branch information
codilion and 0o-de-lally authored Jan 29, 2025
1 parent bfe08b0 commit 22045b0
Show file tree
Hide file tree
Showing 16 changed files with 375 additions and 68 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,11 @@ jobs:
cache-all-crates: true
cache-on-failure: true

- uses: actions/[email protected]
with:
name: framework-build
path: framework/

- name: twin
working-directory: ./testsuites/twin
run: cargo test --no-fail-fast
7 changes: 1 addition & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,14 @@
# will have compiled files and executables
**/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# 0L
**/build
**/doc
**/framework_upgrade
# # upgrade fixtures
# **/framework/src/upgrade_fixtures/fixtures/upgrade*
**/head.mrb

sccache.log

Expand Down
1 change: 1 addition & 0 deletions framework/cached-packages/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ fn main() {
prev_dir.join("libra-framework").join("sources").display()
);

// TODO: make this run the libra binary if it is found in users $PATH
ReleaseTarget::Head
.create_release(
false,
Expand Down
41 changes: 39 additions & 2 deletions framework/cached-packages/src/libra_framework_sdk_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#![allow(dead_code)]
#![allow(unused_imports)]
#![allow(clippy::too_many_arguments, clippy::doc_lazy_continuation)]

use diem_types::{
account_address::AccountAddress,
transaction::{EntryFunction, TransactionPayload},
Expand Down Expand Up @@ -260,6 +261,10 @@ pub enum EntryFunctionCall {
id: u64,
},

/// testnet helper to allow testnet root account to set flip the boundary bit
/// used for testing cli tools for polling and triggering
EpochBoundarySmokeEnableTrigger {},

EpochBoundarySmokeTriggerEpoch {},

/// Only a Voucher of the validator can flip the unjail bit.
Expand Down Expand Up @@ -545,7 +550,7 @@ pub enum EntryFunctionCall {
friend_account: AccountAddress,
},

/// will only succesfully vouch if the two are not related by ancestry
/// will only successfully vouch if the two are not related by ancestry
/// prevents spending a vouch that would not be counted.
/// to add a vouch and ignore this check use insist_vouch
VouchVouchFor {
Expand Down Expand Up @@ -706,6 +711,7 @@ impl EntryFunctionCall {
multisig_address,
id,
} => donor_voice_txs_vote_veto_tx(multisig_address, id),
EpochBoundarySmokeEnableTrigger {} => epoch_boundary_smoke_enable_trigger(),
EpochBoundarySmokeTriggerEpoch {} => epoch_boundary_smoke_trigger_epoch(),
JailUnjailByVoucher { addr } => jail_unjail_by_voucher(addr),
LibraCoinClaimMintCapability {} => libra_coin_claim_mint_capability(),
Expand Down Expand Up @@ -1519,6 +1525,23 @@ pub fn donor_voice_txs_vote_veto_tx(
))
}

/// testnet helper to allow testnet root account to set flip the boundary bit
/// used for testing cli tools for polling and triggering
pub fn epoch_boundary_smoke_enable_trigger() -> TransactionPayload {
TransactionPayload::EntryFunction(EntryFunction::new(
ModuleId::new(
AccountAddress::new([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1,
]),
ident_str!("epoch_boundary").to_owned(),
),
ident_str!("smoke_enable_trigger").to_owned(),
vec![],
vec![],
))
}

pub fn epoch_boundary_smoke_trigger_epoch() -> TransactionPayload {
TransactionPayload::EntryFunction(EntryFunction::new(
ModuleId::new(
Expand Down Expand Up @@ -2385,7 +2408,7 @@ pub fn vouch_revoke(friend_account: AccountAddress) -> TransactionPayload {
))
}

/// will only succesfully vouch if the two are not related by ancestry
/// will only successfully vouch if the two are not related by ancestry
/// prevents spending a vouch that would not be counted.
/// to add a vouch and ignore this check use insist_vouch
pub fn vouch_vouch_for(friend_account: AccountAddress) -> TransactionPayload {
Expand Down Expand Up @@ -2762,6 +2785,16 @@ mod decoder {
}
}

pub fn epoch_boundary_smoke_enable_trigger(
payload: &TransactionPayload,
) -> Option<EntryFunctionCall> {
if let TransactionPayload::EntryFunction(_script) = payload {
Some(EntryFunctionCall::EpochBoundarySmokeEnableTrigger {})
} else {
None
}
}

pub fn epoch_boundary_smoke_trigger_epoch(
payload: &TransactionPayload,
) -> Option<EntryFunctionCall> {
Expand Down Expand Up @@ -3397,6 +3430,10 @@ static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy<EntryFunctionDecoderMa
"donor_voice_txs_vote_veto_tx".to_string(),
Box::new(decoder::donor_voice_txs_vote_veto_tx),
);
map.insert(
"epoch_boundary_smoke_enable_trigger".to_string(),
Box::new(decoder::epoch_boundary_smoke_enable_trigger),
);
map.insert(
"epoch_boundary_smoke_trigger_epoch".to_string(),
Box::new(decoder::epoch_boundary_smoke_trigger_epoch),
Expand Down
53 changes: 40 additions & 13 deletions framework/libra-framework/sources/ol_sources/epoch_boundary.move
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ module diem_framework::epoch_boundary {
// Just like a dream, you are not what you seem
// Just like a prayer, no choice your voice can take me there...
move_to(&framework_signer, BoundaryBit {
closing_epoch: closing_epoch,
closing_epoch,
ready: true,
})
} else {
Expand All @@ -226,15 +226,12 @@ module diem_framework::epoch_boundary {
/// by a user, would not cause a halt.
public(friend) fun trigger_epoch(framework_signer: &signer)
acquires BoundaryBit, BoundaryStatus {
// COMMIT NOTE: there's no reason to gate this, if th trigger is not
// ready (which only happens on Main and Stage, then user will get an error)
// assert!(!testnet::is_testnet(), ETRIGGER_EPOCH_MAINNET);
// must get root permission from governance.move
system_addresses::assert_diem_framework(framework_signer);
let _ = can_trigger(); // will abort if false
let _ = assert_can_trigger(); // will abort if false

// update the state and flip the Bit
// note we are using the 0x0 address for BoundaryBit
// note we are using the 0x1 address for BoundaryBit
let state = borrow_global_mut<BoundaryBit>(@ol_framework);
state.ready = false;

Expand All @@ -253,16 +250,45 @@ module diem_framework::epoch_boundary {
epoch_boundary(framework_signer, state.closing_epoch, 0);
}

/// testnet helper to allow testnet root account to set flip the boundary bit
/// used for testing cli tools for polling and triggering
public entry fun smoke_enable_trigger(core_resource: &signer)
acquires BoundaryBit {
// cannot call this on mainnet
// only for smoke testing
assert!(testnet::is_not_mainnet(), ETRIGGER_EPOCH_UNAUTHORIZED);
// core_resource account is the the tesnet account with root permissions
system_addresses::assert_core_resource(core_resource);
let state = borrow_global_mut<BoundaryBit>(@ol_framework);
state.closing_epoch = reconfiguration::get_current_epoch();
state.ready = true;
}


#[view]
/// check to see if the epoch BoundaryBit is true
public fun can_trigger(): bool acquires BoundaryBit {
/// API view for triggering which does not abort
public fun can_trigger():bool acquires BoundaryBit {
let state = borrow_global_mut<BoundaryBit>(@ol_framework);
if (state.ready &&
// greater than or equal because in case there is an epoch change due to an epoch bump in
// testnet Twin tools, or a rescue operation.
state.closing_epoch <= reconfiguration::get_current_epoch()){
return true
};

false
}

/// assert and abort with failure reason for trigger
fun assert_can_trigger(): bool acquires BoundaryBit {
let state = borrow_global_mut<BoundaryBit>(@ol_framework);
assert!(state.ready, ETRIGGER_NOT_READY);
// greater than, in case there is an epoch change due to an epoch bump in
// greater than or equal because in case there is an epoch change due to an epoch bump in
// testnet Twin tools, or a rescue operation.
assert!(state.closing_epoch <= reconfiguration::get_current_epoch(),
ENOT_SAME_EPOCH);
true

can_trigger()
}

// This function handles the necessary migrations that occur at the epoch boundary
Expand All @@ -272,9 +298,10 @@ module diem_framework::epoch_boundary {
migrations::execute(framework);
}

// Contains all of 0L's business logic for end of epoch.
// This removed business logic from reconfiguration.move
// and prevents dependency cycling.
/// Contains all of 0L's business logic for end of epoch.
/// This removed business logic from reconfiguration.move
/// and prevents dependency cycling.
// TODO: do we need closing_epoch if there is no depedency cycling with reconfiguration::
public(friend) fun epoch_boundary(root: &signer, closing_epoch: u64, epoch_round: u64)
acquires BoundaryStatus {
print(&string::utf8(b"EPOCH BOUNDARY BEGINS"));
Expand Down
Binary file removed framework/releases/head.mrb
Binary file not shown.
36 changes: 11 additions & 25 deletions tools/query/src/chain_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
use crate::query_view::{self, get_view};
use anyhow::Context;
use diem_sdk::rest_client::{diem_api_types::ViewRequest, Client};
use libra_types::type_extensions::client_ext::entry_function_id;
use diem_sdk::rest_client::Client;

/// Retrieves the current epoch from the blockchain.
pub async fn get_epoch(client: &Client) -> anyhow::Result<u64> {
Expand All @@ -21,29 +20,7 @@ pub async fn get_epoch(client: &Client) -> anyhow::Result<u64> {
Ok(num)
}

/// helper to get libra balance at a SlowWalletBalance type which shows
/// total balance and the unlocked balance.
pub async fn get_tower_difficulty(client: &Client) -> anyhow::Result<(u64, u64)> {
let slow_balance_id = entry_function_id("tower_state", "get_difficulty")?;
let request = ViewRequest {
function: slow_balance_id,
type_arguments: vec![],
arguments: vec![],
};

let res = client.view(&request, None).await?.into_inner();

// TODO: Gross.
let difficulty: u64 =
serde_json::from_value::<String>(res.first().context("no difficulty returned")?.clone())?
.parse()?;
let security: u64 = serde_json::from_value::<String>(
res.get(1).context("no security param returned")?.clone(),
)?
.parse()?;

Ok((difficulty, security))
}
// COMMIT NOTE: deprecated tower functions

/// Retrieves the ID of the next governance proposal.
pub async fn get_next_governance_proposal_id(client: &Client) -> anyhow::Result<u64> {
Expand Down Expand Up @@ -115,3 +92,12 @@ pub async fn get_height(client: &Client) -> anyhow::Result<u64> {

Ok(height)
}

/// Retrieves the current blockchain height.
pub async fn epoch_over_can_trigger(client: &Client) -> anyhow::Result<bool> {
let res = get_view(client, "0x1::epoch_boundary::can_trigger", None, None).await?;

let value: Vec<bool> = serde_json::from_value(res)?;

Ok(value[0])
}
2 changes: 2 additions & 0 deletions tools/txs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
pub mod constants;
pub mod generic_tx;
pub mod publish;
pub mod stream;
pub mod submit_transaction;
pub mod transfer;
pub mod txs_cli;
pub mod txs_cli_community;
pub mod txs_cli_governance;
pub mod txs_cli_stream;
pub mod txs_cli_user;
pub mod txs_cli_vals;
8 changes: 8 additions & 0 deletions tools/txs/src/stream/bid_commit_reveal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#[derive(clap::Args)]
pub struct PofBidArgs {
#[clap(short, long)]
pub net_reward: u64,

#[clap(short, long)]
pub test_private_key: Option<String>,
}
37 changes: 37 additions & 0 deletions tools/txs/src/stream/epoch_tickle_poll.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use diem_logger::info;
use diem_types::transaction::TransactionPayload;
use libra_cached_packages::libra_stdlib;
use libra_types::exports::Client;
use std::borrow::BorrowMut;
use std::sync::mpsc::Sender;
use std::thread;
use std::time::Duration;

pub fn epoch_tickle_poll(mut tx: Sender<TransactionPayload>, client: Client, delay_secs: u64) {
println!("polling epoch boundary");
let handle = thread::spawn(move || loop {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();

// TODO: make the client borrow instead of clone
let res = rt.block_on(libra_query::chain_queries::epoch_over_can_trigger(
&client.clone(),
));

match res {
Ok(true) => {
let func = libra_stdlib::diem_governance_trigger_epoch();

tx.borrow_mut().send(func).unwrap();
}
_ => {
info!("Not ready to call epoch.")
}
}

thread::sleep(Duration::from_secs(delay_secs));
});
handle.join().expect("cannot poll for epoch boundary");
}
1 change: 1 addition & 0 deletions tools/txs/src/stream/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod epoch_tickle_poll;
16 changes: 15 additions & 1 deletion tools/txs/src/submit_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,25 @@ impl Sender {
println!("transaction sent");
self.response = Some(r.clone());
spin.finish_and_clear();
debug!("{:?}", &r);
// debug!("{:?}", &r);
OLProgress::complete("transaction success");
Ok(r)
}

/// sync helper for sending tx
pub fn sync_sign_submit_wait(
&mut self,
payload: TransactionPayload,
) -> anyhow::Result<TransactionOnChainData> {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();

// Call the asynchronous connect method using the runtime.
rt.block_on(self.sign_submit_wait(payload))
}

/// Signs a transaction payload.
pub fn sign_payload(&mut self, payload: TransactionPayload) -> SignedTransaction {
let t = SystemTime::now()
Expand Down
Loading

0 comments on commit 22045b0

Please sign in to comment.