#![allow(
clippy::unreadable_literal,
clippy::upper_case_acronyms,
dead_code,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
overflowing_literals,
unused_variables,
unused_assignments
)]
use ethereum_types::U256;
use rustc_hex::ToHex;
use serde_json::{json, Value as JsonValue};
use time::Tm;
use crate::bcossdk::accountutil::{account_from_pem, BcosAccount};
use crate::bcossdk::bcosclientconfig::BcosClientProtocol;
use crate::bcossdk::bcosclientconfig::{BcosCryptoKind, ClientConfig};
use crate::bcossdk::bcosrpcwraper::BcosRPC;
use crate::bcossdk::bcostransaction::{BcosTransaction, BcosTransactionWithSig};
use crate::bcossdk::commonhash::{CommonHash, HashType};
use crate::bcossdk::commonsigner::{
CommonSignerWeDPR_SM2, CommonSignerWeDPR_Secp256, ICommonSigner,
};
use crate::bcossdk::contractabi::ContractABI;
use crate::bcossdk::fileutils;
use crate::bcossdk::kisserror::{KissErrKind, KissError};
#[derive()]
pub struct BcosSDK {
pub config: ClientConfig,
pub account: BcosAccount,
pub netclient: BcosRPC,
pub ecdsasigner: Option<CommonSignerWeDPR_Secp256>,
pub gmsigner: Option<CommonSignerWeDPR_SM2>,
pub hashtype: HashType,
pub updateblocknum_tick: Tm,
pub lastblocknum: u32,
}
impl BcosSDK {
pub fn to_summary(&self) -> String {
let basic = format!(
"Crypto kind:{:?},configfile:{}",
&self.config.chain.crypto,
&self.config.configfile.as_ref().unwrap()
);
let protocol;
match self.config.chain.protocol {
BcosClientProtocol::RPC => {
protocol = format!("RPC:{}", self.config.rpc.url);
}
BcosClientProtocol::CHANNEL => {
protocol = format!(
"Channel:{}:{}({:?})",
&self.config.channel.ip, self.config.channel.port, &self.config.channel.tlskind
);
}
}
let full = format!("{},{}", protocol, basic);
return full;
}
pub fn new_from_config(configfile: &str) -> Result<BcosSDK, KissError> {
let config = ClientConfig::load(configfile)?;
printlnex!("config is {:?}", config);
let hashtype = CommonHash::crypto_to_hashtype(&config.chain.crypto);
let mut ecdsasigner = Option::None;
let mut gmsigner = Option::None;
let account = account_from_pem(config.chain.accountpem.as_str(), &config.chain.crypto)?;
match &config.chain.crypto {
BcosCryptoKind::ECDSA => {
let mut signer = CommonSignerWeDPR_Secp256::default();
signer.account = account.clone();
ecdsasigner = Option::from(signer);
}
BcosCryptoKind::GM => {
let mut signer = CommonSignerWeDPR_SM2::default();
signer.account = account.clone();
gmsigner = Option::from(signer);
}
}
let netclient = BcosRPC::new(&config)?;
Ok(BcosSDK {
config,
account,
netclient,
gmsigner: gmsigner.clone(),
ecdsasigner: ecdsasigner.clone(),
hashtype: hashtype.clone(),
updateblocknum_tick: time::now() - chrono::Duration::seconds(500),
lastblocknum: 0,
})
}
pub fn new() -> Result<BcosSDK, KissError> {
let configfile = "conf/config.toml";
BcosSDK::new_from_config(configfile)
}
pub fn finish(&mut self) {
self.netclient.finish();
}
pub fn deploy_hexcode(&mut self, hexcode: &str) -> Result<JsonValue, KissError> {
let block_limit = self.getBlockLimit()?;
let to_address = "".to_string();
let tx = self.make_transaction(&to_address, &hexcode, block_limit);
let groupid = self.config.chain.groupid;
let cmd = "sendRawTransaction";
let rawdata = self.encode_sign_raw_tx(&tx.unwrap())?;
let hexdata = rawdata.to_hex();
let paramobj = json!([groupid, hexdata]);
let value = self.netclient.rpc_request_sync(cmd, ¶mobj)?;
Ok(value)
}
pub fn deploy_file(&mut self, binfile: &str, params: &str) -> Result<JsonValue, KissError> {
let hexcode = fileutils::readstring(binfile)?;
let codewithparam = format!("{}{}", hexcode, params); self.deploy_hexcode(codewithparam.as_str())
}
pub fn deploy_code_withparam(
&mut self,
hexcode: &str,
contractname: &str,
params_array: &[String],
) -> Result<JsonValue, KissError> {
let contract = ContractABI::new_by_name(
contractname,
self.config.contract.contractpath.as_str(),
&CommonHash::crypto_to_hashtype(&self.config.chain.crypto),
)?;
let paramcode = contract
.encode_construtor_input("".as_bytes().to_vec(), ¶ms_array, true)
.unwrap();
let codewithparam = format!("{}{}", hexcode, paramcode); self.deploy_hexcode(codewithparam.as_str())
}
pub fn deploy_withparam(
&mut self,
contractname: &str,
params_array: &[String],
) -> Result<JsonValue, KissError> {
let contract = ContractABI::new_by_name(
contractname,
self.config.contract.contractpath.as_str(),
&CommonHash::crypto_to_hashtype(&self.config.chain.crypto),
)?;
let paramcode = contract
.encode_construtor_input("".as_bytes().to_vec(), ¶ms_array, true)
.unwrap();
let binfile = format!(
"{}/{}.bin",
self.config.contract.contractpath,
contractname.to_string()
);
self.deploy_file(binfile.as_str(), paramcode.as_str())
}
pub fn call(
&mut self,
contract: &ContractABI,
address: &str,
method: &str,
params: &[String],
) -> Result<JsonValue, KissError> {
let groupid = self.config.chain.groupid;
let from = self.account.address.to_hex();
let to = address;
let res = contract.encode_function_input(method, params, true);
let rawdata = match res {
Ok(data) => data,
Err(e) => {
return kisserr!(
KissErrKind::EFormat,
"encode call {:?} error {:?}",
method,
e
)
}
};
let paramobj = json!([groupid,
{"from":from,
"to":to,
"data":rawdata,
"value":0
}]);
let value = self.netclient.rpc_request_sync("call", ¶mobj)?;
Ok(value)
}
pub fn make_transaction(
&self,
to_address: &str,
txinput: &str,
block_limit_i32: u32,
) -> Option<BcosTransaction> {
let randid: u64 = rand::random();
let chainid = self.config.chain.chainid;
let groupid = self.config.chain.groupid;
Option::from(BcosTransaction {
to_address: crate::bcossdk::bcostransaction::encode_address(to_address),
random_id: U256::from(randid),
gas_price: U256::from(30000000),
gas_limit: U256::from(30000000),
block_limit: U256::from(block_limit_i32),
value: U256::from(0),
data: hex::decode(txinput).unwrap(),
fisco_chain_id: U256::from(chainid),
group_id: U256::from(groupid),
extra_data: b"".to_vec(),
hashtype: self.hashtype.clone(), })
}
pub fn pick_signer(&self) -> &dyn ICommonSigner {
match self.config.chain.crypto {
BcosCryptoKind::ECDSA => {
let signer = self.ecdsasigner.as_ref().unwrap();
printlnex!("pick signer {:?}", signer.account.to_hexdetail());
signer
}
BcosCryptoKind::GM => {
let signer = self.gmsigner.as_ref().unwrap();
printlnex!("pick signer {:?}", signer.account.to_hexdetail());
signer
}
}
}
pub fn encode_sign_raw_tx(&self, tx: &BcosTransaction) -> Result<Vec<u8>, KissError> {
let signer = self.pick_signer();
let txsig = BcosTransactionWithSig::sign(signer, tx)?;
let rawdata = txsig.encode();
Ok(rawdata)
}
pub fn send_raw_transaction(
&mut self,
contract: &ContractABI,
to_address: &str,
methodname: &str,
params: &[String],
) -> Result<JsonValue, KissError> {
let block_limit = self.getBlockLimit()?;
let txinput = contract.encode_function_input(methodname, params, true)?;
let tx = self.make_transaction(to_address, &txinput.as_str(), block_limit);
let groupid = self.config.chain.groupid;
let cmd = "sendRawTransaction";
let rawdata = self.encode_sign_raw_tx(&tx.unwrap())?;
let hexdata = rawdata.to_hex();
let paramobj = json!([groupid, hexdata]);
let value = self.netclient.rpc_request_sync(cmd, ¶mobj)?;
Ok(value)
}
pub fn sendRawTransactionAndGetProof(
&mut self,
contract: &ContractABI,
to_address: &str,
methodname: &str,
params: &[String],
) -> Result<JsonValue, KissError> {
let block_limit = self.getBlockLimit()?;
let txinput = contract.encode_function_input(methodname, params, true)?;
let tx = self.make_transaction(to_address, &txinput.as_str(), block_limit);
let groupid = self.config.chain.groupid;
let cmd = "sendRawTransactionAndGetProof";
let rawdata = self.encode_sign_raw_tx(&tx.unwrap())?;
let hexdata = rawdata.to_hex();
let paramobj = json!([groupid, hexdata]);
let value = self.netclient.rpc_request_sync(cmd, ¶mobj)?;
Ok(value)
}
}