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

cmd/starcoin: try to generate sign file when found multisig account in txn execution process #3461

Merged
merged 7 commits into from
Jun 16, 2022
11 changes: 7 additions & 4 deletions cmd/starcoin/src/account/execute_script_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
// Copyright (c) The Starcoin Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::cli_state::CliState;
use crate::view::{ExecuteResultView, TransactionOptions};
use crate::StarcoinOpt;
use std::path::PathBuf;

use anyhow::{bail, Result};
use clap::Parser;

use scmd::{CommandAction, ExecContext};
use starcoin_move_compiler::load_bytecode_file;
use starcoin_types::transaction::{
parse_transaction_argument, Script, TransactionArgument, TransactionPayload,
};
use starcoin_vm_types::transaction_argument::convert_txn_args;
use starcoin_vm_types::{language_storage::TypeTag, parser::parse_type_tag};
use std::path::PathBuf;

use crate::cli_state::CliState;
use crate::view::{ExecuteResultView, TransactionOptions};
use crate::StarcoinOpt;

/// Execute a script
#[derive(Debug, Parser)]
Expand Down
66 changes: 9 additions & 57 deletions cmd/starcoin/src/account/sign_multisig_txn_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@

use std::convert::TryInto;
use std::env::current_dir;
use std::fs::File;
use std::path::PathBuf;

use anyhow::{bail, Result};
use clap::Parser;
use starcoin_crypto::hash::PlainCryptoHash;
use starcoin_crypto::multi_ed25519::multi_shard::MultiEd25519SignatureShard;

use scmd::{CommandAction, ExecContext};
Expand All @@ -28,6 +26,7 @@ use starcoin_vm_types::transaction_argument::convert_txn_args;
use starcoin_vm_types::{language_storage::TypeTag, parser::parse_type_tag};

use crate::cli_state::CliState;
use crate::mutlisig_transaction::sign_multisig_txn_to_file;
use crate::StarcoinOpt;

#[derive(Debug, Parser)]
Expand Down Expand Up @@ -213,61 +212,14 @@ impl CommandAction for GenerateMultisigTxnCommand {
}
}
}
let signer_address = raw_txn.sender();
let partial_signed_txn = account_client.sign_txn(raw_txn, signer_address)?;
let my_signatures = if let TransactionAuthenticator::MultiEd25519 { signature, .. } =
partial_signed_txn.authenticator()
{
MultiEd25519SignatureShard::new(signature, *account_public_key.threshold())
} else {
unreachable!()
};

// merge my signatures with existing signatures of other participants.
let merged_signatures = {
let mut signatures = vec![];
if let Some(s) = existing_signatures {
signatures.push(s);
}
signatures.push(my_signatures);
MultiEd25519SignatureShard::merge(signatures)?
};
eprintln!(
"mutlisig txn(address: {}, threshold: {}): {} signatures collected",
sender,
merged_signatures.threshold(),
merged_signatures.signatures().len()
);
if !merged_signatures.is_enough() {
eprintln!(
"still require {} signatures",
merged_signatures.threshold() as usize - merged_signatures.signatures().len()
);
} else {
eprintln!("enough signatures collected for the multisig txn, txn can be submitted now");
}

// construct the signed txn with merged signatures.
let signed_txn = {
let authenticator = TransactionAuthenticator::MultiEd25519 {
public_key: account_public_key,
signature: merged_signatures.into(),
};
SignedUserTransaction::new(partial_signed_txn.into_raw_transaction(), authenticator)
};

// output the txn, send this to other participants to sign, or just submit it.
let output_file = {
let mut output_dir = opt.output_dir.clone().unwrap_or(current_dir()?);
// use hash's as output file name
let file_name = signed_txn.crypto_hash().to_hex();
output_dir.push(file_name);
output_dir.set_extension("multisig-txn");
output_dir
};
let mut file = File::create(output_file.clone())?;
// write txn to file
bcs_ext::serialize_into(&mut file, &signed_txn)?;
Ok(output_file)
let output_dir = opt.output_dir.clone().unwrap_or(current_dir()?);
sign_multisig_txn_to_file(
raw_txn.sender(),
account_public_key,
existing_signatures,
account_client.sign_txn(raw_txn, sender)?,
output_dir,
)
}
}
57 changes: 41 additions & 16 deletions cmd/starcoin/src/cli_state.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
// Copyright (c) The Starcoin Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::view::{ExecuteResultView, ExecutionOutputView, TransactionOptions};
use std::convert::TryInto;
use std::env::current_dir;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::Duration;

use anyhow::{bail, format_err, Result};
use bcs_ext::BCSCodec;
use serde::de::DeserializeOwned;
use starcoin_crypto::HashValue;

use bcs_ext::BCSCodec;
use starcoin_abi_decoder::{decode_txn_payload, DecodedTransactionPayload};
use starcoin_account_api::{AccountInfo, AccountProvider};
use starcoin_config::{ChainNetworkID, DataDirPath};
use starcoin_crypto::HashValue;
use starcoin_node::NodeHandle;
use starcoin_rpc_api::chain::GetEventOption;
use starcoin_rpc_api::types::{RawUserTransactionView, TransactionStatusView};
Expand All @@ -19,11 +25,11 @@ use starcoin_vm_types::account_address::AccountAddress;
use starcoin_vm_types::account_config::association_address;
use starcoin_vm_types::move_resource::MoveResource;
use starcoin_vm_types::token::stc::STC_TOKEN_CODE_STR;
use starcoin_vm_types::transaction::authenticator::AccountPublicKey;
use starcoin_vm_types::transaction::{DryRunTransaction, RawUserTransaction, TransactionPayload};
use std::convert::TryInto;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::Duration;

use crate::mutlisig_transaction::sign_multisig_txn_to_file;
use crate::view::{ExecuteResultView, ExecutionOutputView, TransactionOptions};

static G_HISTORY_FILE_NAME: &str = "history";

Expand Down Expand Up @@ -252,8 +258,9 @@ impl CliState {
blocking: bool,
) -> Result<ExecuteResultView> {
let sender = self.get_account(raw_txn.sender())?;
let public_key = sender.public_key;
let dry_output = self.client.dry_run_raw(DryRunTransaction {
public_key: sender.public_key,
public_key: public_key.clone(),
raw_txn: raw_txn.clone(),
})?;
let mut raw_txn_view: RawUserTransactionView = raw_txn.clone().try_into()?;
Expand All @@ -270,16 +277,34 @@ impl CliState {
eprintln!("txn dry run failed");
return Ok(execute_result);
}

let signed_txn = self.account_client.sign_txn(raw_txn, sender.address)?;
let signed_txn_hex = hex::encode(signed_txn.encode()?);
let txn_hash = self.client.submit_hex_transaction(signed_txn_hex)?;
eprintln!("txn {} submitted.", txn_hash);
let execute_output = if blocking {
self.watch_txn(txn_hash)?
} else {
ExecutionOutputView::new(txn_hash)

let multisig_public_key = match &public_key {
AccountPublicKey::Single(_) => {
let signed_txn_hex = hex::encode(signed_txn.encode()?);
let txn_hash = self.client.submit_hex_transaction(signed_txn_hex)?;
eprintln!("txn {} submitted.", txn_hash);
let execute_output = if blocking {
self.watch_txn(txn_hash)?
} else {
ExecutionOutputView::new(txn_hash)
};
execute_result.execute_output = Some(execute_output);
return Ok(execute_result);
}

AccountPublicKey::Multi(m) => m.clone(),
};
execute_result.execute_output = Some(execute_output);

let _ = sign_multisig_txn_to_file(
sender.address,
multisig_public_key,
None,
signed_txn,
current_dir()?,
);

Ok(execute_result)
}

Expand Down
74 changes: 73 additions & 1 deletion cmd/starcoin/src/mutlisig_transaction.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;

use anyhow::Result;
use serde::{Deserialize, Serialize};
use starcoin_crypto::ed25519::{Ed25519PublicKey, Ed25519Signature};
use starcoin_crypto::hash::PlainCryptoHash;
use starcoin_crypto::multi_ed25519::multi_shard::MultiEd25519SignatureShard;
use starcoin_crypto::multi_ed25519::{MultiEd25519PublicKey, MultiEd25519Signature};

use starcoin_types::account_address::AccountAddress;
use starcoin_vm_types::transaction::authenticator::TransactionAuthenticator;
use starcoin_vm_types::transaction::{RawUserTransaction, SignedUserTransaction};
use std::collections::HashMap;

#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub struct MultisigTransaction {
raw_txn: RawUserTransaction,
Expand Down Expand Up @@ -81,3 +90,66 @@ impl MultisigTransaction {
))
}
}

pub fn sign_multisig_txn_to_file(
sender: AccountAddress,
multisig_public_key: MultiEd25519PublicKey,
existing_signatures: Option<MultiEd25519SignatureShard>,
partial_signed_txn: SignedUserTransaction,
output_dir: PathBuf,
) -> Result<PathBuf> {
let my_signatures = if let TransactionAuthenticator::MultiEd25519 { signature, .. } =
partial_signed_txn.authenticator()
{
MultiEd25519SignatureShard::new(signature, *multisig_public_key.threshold())
} else {
unreachable!()
};

// merge my signatures with existing signatures of other participants.
let merged_signatures = {
let mut signatures = vec![];
if let Some(s) = existing_signatures {
signatures.push(s);
}
signatures.push(my_signatures);
MultiEd25519SignatureShard::merge(signatures)?
};
eprintln!(
"mutlisig txn(address: {}, threshold: {}): {} signatures collected",
sender,
merged_signatures.threshold(),
merged_signatures.signatures().len()
);
if !merged_signatures.is_enough() {
eprintln!(
"still require {} signatures",
merged_signatures.threshold() as usize - merged_signatures.signatures().len()
);
} else {
eprintln!("enough signatures collected for the multisig txn, txn can be submitted now");
}

// construct the signed txn with merged signatures.
let signed_txn = {
let authenticator = TransactionAuthenticator::MultiEd25519 {
public_key: multisig_public_key,
signature: merged_signatures.into(),
};
SignedUserTransaction::new(partial_signed_txn.into_raw_transaction(), authenticator)
};

// output the txn, send this to other participants to sign, or just submit it.
let output_file = {
let mut output_dir = output_dir;
// use hash's as output file name
let file_name = signed_txn.crypto_hash().to_hex();
output_dir.push(file_name);
output_dir.set_extension("multisig-txn");
output_dir
};
let mut file = File::create(output_file.clone())?;
// write txn to file
bcs_ext::serialize_into(&mut file, &signed_txn)?;
Ok(output_file)
}