use std::convert::{TryFrom, TryInto};
use ergo_lib::{
chain,
ergo_chain_types::{Base16DecodedBytes, Base16EncodedBytes},
};
use crate::{
collections::{Collection, CollectionPtr, ConstCollectionPtr},
data_input::DataInput,
ergo_box::{ErgoBox, ErgoBoxCandidate},
ergo_state_ctx::ConstErgoStateContextPtr,
input::{Input, UnsignedInput},
json::{TransactionJsonEip12, UnsignedTransactionJsonEip12},
reduced::ConstPropositionsPtr,
util::{const_ptr_as_ref, mut_ptr_as_mut, ByteArray},
Error,
};
pub struct CommitmentHint(
pub(crate) ergo_lib::ergotree_interpreter::sigma_protocol::prover::hint::CommitmentHint,
);
pub type CommitmentHintPtr = *mut CommitmentHint;
pub type ConstCommitmentHintPtr = *const CommitmentHint;
pub struct HintsBag(
pub(crate) ergo_lib::ergotree_interpreter::sigma_protocol::prover::hint::HintsBag,
);
pub type HintsBagPtr = *mut HintsBag;
pub type ConstHintsBagPtr = *const HintsBag;
pub unsafe fn hints_bag_empty(hints_bag_out: *mut HintsBagPtr) -> Result<(), Error> {
let hints_bag_out = mut_ptr_as_mut(hints_bag_out, "hints_bag_out")?;
*hints_bag_out = Box::into_raw(Box::new(HintsBag(
ergo_lib::ergotree_interpreter::sigma_protocol::prover::hint::HintsBag::empty(),
)));
Ok(())
}
pub unsafe fn hints_bag_add_commitment(
hints_bag_mut: HintsBagPtr,
hint_ptr: ConstCommitmentHintPtr,
) -> Result<(), Error> {
let hints_bag_mut = mut_ptr_as_mut(hints_bag_mut, "hints_bag_mut")?;
let hint = const_ptr_as_ref(hint_ptr, "hint_ptr")?;
hints_bag_mut.0.add_hint(
ergo_lib::ergotree_interpreter::sigma_protocol::prover::hint::Hint::CommitmentHint(
hint.0.clone(),
),
);
Ok(())
}
pub unsafe fn hints_bag_len(hints_bag_ptr: ConstHintsBagPtr) -> Result<usize, Error> {
let hints_bag = const_ptr_as_ref(hints_bag_ptr, "hints_bag_ptr")?;
Ok(hints_bag.0.hints.len())
}
pub unsafe fn hints_bag_get(
hints_bag_ptr: ConstHintsBagPtr,
index: usize,
hint_out: *mut CommitmentHintPtr,
) -> Result<bool, Error> {
let hints_bag = const_ptr_as_ref(hints_bag_ptr, "hints_bag_ptr")?;
let hint_out = mut_ptr_as_mut(hint_out, "hint_out")?;
if let Some(commitment) = hints_bag.0.commitments().get(index) {
*hint_out = Box::into_raw(Box::new(CommitmentHint(commitment.clone())));
return Ok(true);
}
Ok(false)
}
pub struct TransactionHintsBag(pub(crate) ergo_lib::wallet::multi_sig::TransactionHintsBag);
pub type TransactionHintsBagPtr = *mut TransactionHintsBag;
pub type ConstTransactionHintsBagPtr = *const TransactionHintsBag;
pub unsafe fn transaction_hints_bag_empty(
transaction_hints_bag_out: *mut TransactionHintsBagPtr,
) -> Result<(), Error> {
let transaction_hints_bag_out =
mut_ptr_as_mut(transaction_hints_bag_out, "transaction_hints_bag_out")?;
*transaction_hints_bag_out = Box::into_raw(Box::new(TransactionHintsBag(
ergo_lib::wallet::multi_sig::TransactionHintsBag::empty(),
)));
Ok(())
}
pub unsafe fn transaction_hints_bag_add_hints_for_input(
transaction_hints_bag_mut: TransactionHintsBagPtr,
index: usize,
hints_bag_ptr: ConstHintsBagPtr,
) -> Result<(), Error> {
let transaction_hints_bag_mut =
mut_ptr_as_mut(transaction_hints_bag_mut, "transaction_hints_bag_mut")?;
let hints_bag = const_ptr_as_ref(hints_bag_ptr, "hints_bag_ptr")?;
transaction_hints_bag_mut
.0
.add_hints_for_input(index, hints_bag.0.clone());
Ok(())
}
pub unsafe fn transaction_hints_bag_all_hints_for_input(
transaction_hints_bag_ptr: ConstTransactionHintsBagPtr,
index: usize,
hints_bag_out: *mut HintsBagPtr,
) -> Result<(), Error> {
let transaction_hints_bag =
const_ptr_as_ref(transaction_hints_bag_ptr, "transaction_hints_bag_ptr")?;
let hints_bag_out = mut_ptr_as_mut(hints_bag_out, "hints_bag_out")?;
*hints_bag_out = Box::into_raw(Box::new(HintsBag(
transaction_hints_bag.0.all_hints_for_input(index),
)));
Ok(())
}
pub unsafe fn transaction_extract_hints(
signed_transaction_ptr: ConstTransactionPtr,
state_context_ptr: ConstErgoStateContextPtr,
boxes_to_spend_ptr: ConstCollectionPtr<ErgoBox>,
data_boxes_ptr: ConstCollectionPtr<ErgoBox>,
real_propositions_ptr: ConstPropositionsPtr,
simulated_propositions_ptr: ConstPropositionsPtr,
transaction_hints_bag_out: *mut TransactionHintsBagPtr,
) -> Result<(), Error> {
let signed_transaction = const_ptr_as_ref(signed_transaction_ptr, "signed_transaction_ptr")?;
let state_context = const_ptr_as_ref(state_context_ptr, "state_context_ptr")?;
let boxes_to_spend = const_ptr_as_ref(boxes_to_spend_ptr, "boxes_to_spend_ptr")?;
let data_boxes = const_ptr_as_ref(data_boxes_ptr, "data_boxes_ptr")?;
let real_propositions = const_ptr_as_ref(real_propositions_ptr, "real_propositions_ptr")?;
let simulated_propositions =
const_ptr_as_ref(simulated_propositions_ptr, "simulated_propositions_ptr")?;
let transaction_hints_bag_out =
mut_ptr_as_mut(transaction_hints_bag_out, "transaction_hints_bag_out")?;
let boxes_to_spend = boxes_to_spend.0.clone().into_iter().map(|x| x.0).collect();
let data_boxes = data_boxes.0.clone().into_iter().map(|x| x.0).collect();
let tx_context = ergo_lib::wallet::signing::TransactionContext::new(
signed_transaction.0.clone(),
boxes_to_spend,
data_boxes,
)?;
*transaction_hints_bag_out = Box::into_raw(Box::new(TransactionHintsBag(
ergo_lib::wallet::multi_sig::extract_hints(
&tx_context,
&state_context.0.clone(),
real_propositions.0.clone(),
simulated_propositions.0.clone(),
)?,
)));
Ok(())
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct UnsignedTransaction(pub(crate) chain::transaction::unsigned::UnsignedTransaction);
pub type UnsignedTransactionPtr = *mut UnsignedTransaction;
pub type ConstUnsignedTransactionPtr = *const UnsignedTransaction;
pub unsafe fn unsigned_tx_id(
unsigned_tx_ptr: ConstUnsignedTransactionPtr,
tx_id_out: *mut TxIdPtr,
) -> Result<(), Error> {
let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
let tx_id_out = mut_ptr_as_mut(tx_id_out, "tx_id_out")?;
*tx_id_out = Box::into_raw(Box::new(TxId(unsigned_tx.0.id())));
Ok(())
}
pub unsafe fn unsigned_tx_inputs(
unsigned_tx_ptr: ConstUnsignedTransactionPtr,
unsigned_inputs_out: *mut CollectionPtr<UnsignedInput>,
) -> Result<(), Error> {
let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
let unsigned_inputs_out = mut_ptr_as_mut(unsigned_inputs_out, "unsigned_inputs_out")?;
*unsigned_inputs_out = Box::into_raw(Box::new(Collection(
unsigned_tx
.0
.inputs
.as_vec()
.clone()
.into_iter()
.map(UnsignedInput)
.collect(),
)));
Ok(())
}
pub unsafe fn unsigned_tx_data_inputs(
unsigned_tx_ptr: ConstUnsignedTransactionPtr,
data_inputs_out: *mut CollectionPtr<DataInput>,
) -> Result<(), Error> {
let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
let data_inputs_out = mut_ptr_as_mut(data_inputs_out, "data_inputs_out")?;
*data_inputs_out = Box::into_raw(Box::new(Collection(
unsigned_tx
.0
.data_inputs
.as_ref()
.map(|v| v.as_vec().clone())
.unwrap_or_else(Vec::new)
.into_iter()
.map(DataInput)
.collect(),
)));
Ok(())
}
pub unsafe fn unsigned_tx_output_candidates(
unsigned_tx_ptr: ConstUnsignedTransactionPtr,
ergo_box_candidates_out: *mut CollectionPtr<ErgoBoxCandidate>,
) -> Result<(), Error> {
let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
let ergo_box_candidates_out =
mut_ptr_as_mut(ergo_box_candidates_out, "ergo_box_candidates_out")?;
*ergo_box_candidates_out = Box::into_raw(Box::new(Collection(
unsigned_tx
.0
.output_candidates
.iter()
.map(|ebc| ErgoBoxCandidate(ebc.clone()))
.collect(),
)));
Ok(())
}
pub unsafe fn unsigned_tx_from_json(
json: &str,
unsigned_tx_out: *mut UnsignedTransactionPtr,
) -> Result<(), Error> {
let unsigned_tx_out = mut_ptr_as_mut(unsigned_tx_out, "unsigned_tx_out")?;
let unsigned_tx = serde_json::from_str(json).map(UnsignedTransaction)?;
*unsigned_tx_out = Box::into_raw(Box::new(unsigned_tx));
Ok(())
}
pub unsafe fn unsigned_tx_to_json(
unsigned_tx_ptr: ConstUnsignedTransactionPtr,
) -> Result<String, Error> {
let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
let s = serde_json::to_string(&unsigned_tx.0)?;
Ok(s)
}
pub unsafe fn unsigned_tx_to_json_eip12(
unsigned_tx_ptr: ConstUnsignedTransactionPtr,
) -> Result<String, Error> {
let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
let tx_dapp: UnsignedTransactionJsonEip12 = unsigned_tx.0.clone().into();
let s = serde_json::to_string(&tx_dapp)?;
Ok(s)
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct TxId(pub(crate) chain::transaction::TxId);
pub type TxIdPtr = *mut TxId;
pub type ConstTxIdPtr = *const TxId;
pub unsafe fn tx_id_from_str(str: &str, tx_id_out: *mut TxIdPtr) -> Result<(), Error> {
let tx_id_out = mut_ptr_as_mut(tx_id_out, "tx_id_out")?;
let bytes = Base16DecodedBytes::try_from(str.to_string())?;
let tx_id = bytes
.try_into()
.map(|digest| TxId(chain::transaction::TxId(digest)))?;
*tx_id_out = Box::into_raw(Box::new(tx_id));
Ok(())
}
pub unsafe fn tx_id_to_str(tx_id_ptr: ConstTxIdPtr) -> Result<String, Error> {
let tx_id = const_ptr_as_ref(tx_id_ptr, "tx_id_ptr")?;
let base16_bytes = Base16EncodedBytes::new(tx_id.0 .0 .0.as_ref());
Ok(base16_bytes.into())
}
pub struct Transaction(pub(crate) chain::transaction::Transaction);
pub type TransactionPtr = *mut Transaction;
pub type ConstTransactionPtr = *const Transaction;
pub unsafe fn tx_from_unsigned_tx(
unsigned_tx_ptr: ConstUnsignedTransactionPtr,
proofs_ptr: ConstCollectionPtr<ByteArray>,
tx_out: *mut TransactionPtr,
) -> Result<(), Error> {
let proofs = const_ptr_as_ref(proofs_ptr, "proofs_ptr")?;
let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
let tx_out = mut_ptr_as_mut(tx_out, "tx_out")?;
let tx = chain::transaction::Transaction::from_unsigned_tx(
unsigned_tx.0.clone(),
proofs
.0
.iter()
.cloned()
.map(|bytes| bytes.0.into())
.collect(),
)
.map(Transaction)?;
*tx_out = Box::into_raw(Box::new(tx));
Ok(())
}
pub unsafe fn tx_id(tx_ptr: ConstTransactionPtr, tx_id_out: *mut TxIdPtr) -> Result<(), Error> {
let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
let tx_id_out = mut_ptr_as_mut(tx_id_out, "tx_id_out")?;
*tx_id_out = Box::into_raw(Box::new(TxId(tx.0.id())));
Ok(())
}
pub unsafe fn tx_from_json(json: &str, tx_out: *mut TransactionPtr) -> Result<(), Error> {
let tx_out = mut_ptr_as_mut(tx_out, "tx_out")?;
let tx = serde_json::from_str(json).map(Transaction)?;
*tx_out = Box::into_raw(Box::new(tx));
Ok(())
}
pub unsafe fn tx_to_json(tx_ptr: ConstTransactionPtr) -> Result<String, Error> {
let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
let s = serde_json::to_string(&tx.0)?;
Ok(s)
}
pub unsafe fn tx_to_json_eip12(tx_ptr: ConstTransactionPtr) -> Result<String, Error> {
let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
let tx_dapp: TransactionJsonEip12 = tx.0.clone().into();
let s = serde_json::to_string(&tx_dapp)?;
Ok(s)
}
pub unsafe fn tx_inputs(
tx_ptr: ConstTransactionPtr,
inputs_out: *mut CollectionPtr<Input>,
) -> Result<(), Error> {
let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
let inputs_out = mut_ptr_as_mut(inputs_out, "inputs_out")?;
*inputs_out = Box::into_raw(Box::new(Collection(
tx.0.inputs
.as_vec()
.clone()
.into_iter()
.map(Input)
.collect(),
)));
Ok(())
}
pub unsafe fn tx_data_inputs(
tx_ptr: ConstTransactionPtr,
data_inputs_out: *mut CollectionPtr<DataInput>,
) -> Result<(), Error> {
let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
let data_inputs_out = mut_ptr_as_mut(data_inputs_out, "data_inputs_out")?;
*data_inputs_out = Box::into_raw(Box::new(Collection(
tx.0.data_inputs
.as_ref()
.map(|v| v.as_vec().clone())
.unwrap_or_else(Vec::new)
.into_iter()
.map(DataInput)
.collect(),
)));
Ok(())
}
pub unsafe fn tx_output_candidates(
tx_ptr: ConstTransactionPtr,
ergo_box_candidates_out: *mut CollectionPtr<ErgoBoxCandidate>,
) -> Result<(), Error> {
let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
let ergo_box_candidates_out =
mut_ptr_as_mut(ergo_box_candidates_out, "ergo_box_candidates_out")?;
*ergo_box_candidates_out = Box::into_raw(Box::new(Collection(
tx.0.output_candidates
.iter()
.map(|ebc| ErgoBoxCandidate(ebc.clone()))
.collect(),
)));
Ok(())
}
pub unsafe fn tx_outputs(
tx_ptr: ConstTransactionPtr,
ergo_box_out: *mut CollectionPtr<ErgoBox>,
) -> Result<(), Error> {
let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
let ergo_box_out = mut_ptr_as_mut(ergo_box_out, "ergo_box_candidates_out")?;
*ergo_box_out = Box::into_raw(Box::new(Collection(
tx.0.outputs
.iter()
.map(|ebc| ErgoBox(ebc.clone()))
.collect(),
)));
Ok(())
}
pub unsafe fn tx_validate(
tx_ptr: ConstTransactionPtr,
state_context_ptr: ConstErgoStateContextPtr,
boxes_to_spend_ptr: ConstCollectionPtr<ErgoBox>,
data_boxes_ptr: ConstCollectionPtr<ErgoBox>,
) -> Result<(), Error> {
let state_context = const_ptr_as_ref(state_context_ptr, "state_context_ptr")?;
let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
let boxes_to_spend = const_ptr_as_ref(boxes_to_spend_ptr, "boxes_to_spend_ptr")?;
let data_boxes = const_ptr_as_ref(data_boxes_ptr, "data_boxes_ptr")?;
let boxes_to_spend = boxes_to_spend.0.clone().into_iter().map(|b| b.0).collect();
let data_boxes = data_boxes.0.clone().into_iter().map(|b| b.0).collect();
let tx_context = ergo_lib::wallet::signing::TransactionContext::new(
tx.0.clone(),
boxes_to_spend,
data_boxes,
)?;
tx_context.validate(&state_context.0)?;
Ok(())
}