Upgrade CLI for mainnet test

This commit is contained in:
Daniel Karzel 2020-12-04 16:27:17 +11:00
parent 9d564b73bf
commit 03b8e5f52e
16 changed files with 478 additions and 59 deletions

View file

@ -20,6 +20,7 @@ genawaiter = "0.99.1"
miniscript = { version = "4", features = ["serde"] }
monero = { version = "0.9", features = ["serde_support"] }
rand = "0.7"
rust_decimal = "1.8"
serde = { version = "1", features = ["derive"] }
sha2 = "0.9"
thiserror = "1"

View file

@ -15,7 +15,14 @@ pub use bitcoin::{util::psbt::PartiallySignedTransaction, *};
pub use ecdsa_fun::{adaptor::EncryptedSignature, fun::Scalar, Signature};
pub use transactions::{TxCancel, TxLock, TxPunish, TxRedeem, TxRefund};
pub const TX_FEE: u64 = 10_000;
// TODO: Configurable tx-fee (note: parties have to agree prior to swapping)
// Current reasoning:
// tx with largest weight (as determined by get_weight() upon broadcast in e2e
// test) = 609 assuming segwit and 60 sat/vB:
// (609 / 4) * 60 (sat/vB) = 9135 sats
// Recommended: Overpay a bit to ensure we don't have to wait too long for test
// runs.
pub const TX_FEE: u64 = 15_000;
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct SecretKey {
@ -212,6 +219,11 @@ pub trait GetRawTransaction {
async fn get_raw_transaction(&self, txid: Txid) -> Result<Transaction>;
}
#[async_trait]
pub trait Network {
fn get_network(&self) -> bitcoin::Network;
}
pub fn recover(S: PublicKey, sig: Signature, encsig: EncryptedSignature) -> Result<SecretKey> {
let adaptor = Adaptor::<Sha256, Deterministic<Sha256>>::default();

View file

@ -1,10 +1,11 @@
use crate::bitcoin::{
build_shared_output_descriptor, verify_sig, BuildTxLockPsbt, OutPoint, PublicKey, Txid, TX_FEE,
build_shared_output_descriptor, verify_sig, BuildTxLockPsbt, Network, OutPoint, PublicKey,
Txid, TX_FEE,
};
use anyhow::{bail, Context, Result};
use bitcoin::{
util::{bip143::SigHashCache, psbt::PartiallySignedTransaction},
Address, Amount, Network, SigHash, SigHashType, Transaction, TxIn, TxOut,
Address, Amount, SigHash, SigHashType, Transaction, TxIn, TxOut,
};
use ecdsa_fun::Signature;
use miniscript::{Descriptor, NullCtx};
@ -20,11 +21,11 @@ pub struct TxLock {
impl TxLock {
pub async fn new<W>(wallet: &W, amount: Amount, A: PublicKey, B: PublicKey) -> Result<Self>
where
W: BuildTxLockPsbt,
W: BuildTxLockPsbt + Network,
{
let lock_output_descriptor = build_shared_output_descriptor(A.0, B.0);
let address = lock_output_descriptor
.address(Network::Regtest, NullCtx)
.address(wallet.get_network(), NullCtx)
.expect("can derive address from descriptor");
// We construct a psbt for convenience

View file

@ -33,7 +33,7 @@ use tracing::error;
pub mod message;
use crate::{
bitcoin::{BlockHeight, GetRawTransaction, TransactionBlockHeight},
bitcoin::{BlockHeight, GetRawTransaction, Network, TransactionBlockHeight},
monero::{CreateWalletForOutput, WatchForTransfer},
};
use ::bitcoin::{Transaction, Txid};
@ -267,7 +267,7 @@ where
// send to one receive in the correct order.
pub async fn next_state<
R: RngCore + CryptoRng,
B: WatchForRawTransaction + SignTxLock + BuildTxLockPsbt + BroadcastSignedTransaction,
B: WatchForRawTransaction + SignTxLock + BuildTxLockPsbt + BroadcastSignedTransaction + Network,
M: CreateWalletForOutput + WatchForTransfer,
T: SendMessage<Message> + ReceiveMessage<alice::Message>,
>(
@ -401,7 +401,7 @@ impl State0 {
pub async fn receive<W>(self, wallet: &W, msg: alice::Message0) -> anyhow::Result<State1>
where
W: BuildTxLockPsbt,
W: BuildTxLockPsbt + Network,
{
msg.dleq_proof_s_a.verify(
msg.S_a_bitcoin.clone().into(),

View file

@ -9,6 +9,7 @@ pub struct Config {
pub monero_max_finality_time: Duration,
pub bitcoin_refund_timelock: u32,
pub bitcoin_punish_timelock: u32,
pub bitcoin_network: ::bitcoin::Network,
}
impl Config {
@ -23,6 +24,7 @@ impl Config {
* mainnet::MONERO_FINALITY_CONFIRMATIONS,
bitcoin_refund_timelock: mainnet::BITCOIN_REFUND_TIMELOCK,
bitcoin_punish_timelock: mainnet::BITCOIN_PUNISH_TIMELOCK,
bitcoin_network: ::bitcoin::Network::Bitcoin,
}
}
@ -37,6 +39,7 @@ impl Config {
* regtest::MONERO_FINALITY_CONFIRMATIONS,
bitcoin_refund_timelock: regtest::BITCOIN_REFUND_TIMELOCK,
bitcoin_punish_timelock: regtest::BITCOIN_PUNISH_TIMELOCK,
bitcoin_network: ::bitcoin::Network::Regtest,
}
}
}

View file

@ -5,10 +5,17 @@ use rand::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};
use std::ops::{Add, Mul, Sub};
use bitcoin::hashes::core::fmt::Formatter;
pub use curve25519_dalek::scalar::Scalar;
pub use monero::*;
use rust_decimal::{
prelude::{FromPrimitive, ToPrimitive},
Decimal,
};
use std::{fmt::Display, str::FromStr};
pub const MIN_CONFIRMATIONS: u32 = 10;
pub const PICONERO_OFFSET: u64 = 1_000_000_000_000;
pub fn random_private_key<R: RngCore + CryptoRng>(rng: &mut R) -> PrivateKey {
let scalar = Scalar::random(rng);
@ -76,9 +83,20 @@ impl Amount {
pub fn from_piconero(amount: u64) -> Self {
Amount(amount)
}
pub fn as_piconero(&self) -> u64 {
self.0
}
pub fn parse_monero(amount: &str) -> Result<Self> {
let decimal = Decimal::from_str(amount)?;
let piconeros_dec =
decimal.mul(Decimal::from_u64(PICONERO_OFFSET).expect("constant to fit into u64"));
let piconeros = piconeros_dec
.to_u64()
.ok_or_else(|| OverflowError(amount.to_owned()))?;
Ok(Amount(piconeros))
}
}
impl Add for Amount {
@ -111,6 +129,16 @@ impl From<Amount> for u64 {
}
}
impl Display for Amount {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut decimal = Decimal::from(self.0);
decimal
.set_scale(12)
.expect("12 is smaller than max precision of 28");
write!(f, "{} XMR", decimal)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TransferProof {
tx_hash: TxHash,
@ -177,3 +205,70 @@ pub trait CreateWalletForOutput {
private_view_key: PrivateViewKey,
) -> anyhow::Result<()>;
}
#[derive(thiserror::Error, Debug, Clone, PartialEq)]
#[error("Overflow, cannot convert {0} to u64")]
pub struct OverflowError(pub String);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_monero_min() {
let min_pics = 1;
let amount = Amount::from_piconero(min_pics);
let monero = amount.to_string();
assert_eq!("0.000000000001 XMR", monero);
}
#[test]
fn display_monero_one() {
let min_pics = 1000000000000;
let amount = Amount::from_piconero(min_pics);
let monero = amount.to_string();
assert_eq!("1.000000000000 XMR", monero);
}
#[test]
fn display_monero_max() {
let max_pics = 18_446_744_073_709_551_615;
let amount = Amount::from_piconero(max_pics);
let monero = amount.to_string();
assert_eq!("18446744.073709551615 XMR", monero);
}
#[test]
fn parse_monero_min() {
let monero_min = "0.000000000001";
let amount = Amount::parse_monero(monero_min).unwrap();
let pics = amount.0;
assert_eq!(1, pics);
}
#[test]
fn parse_monero() {
let monero = "123";
let amount = Amount::parse_monero(monero).unwrap();
let pics = amount.0;
assert_eq!(123000000000000, pics);
}
#[test]
fn parse_monero_max() {
let monero = "18446744.073709551615";
let amount = Amount::parse_monero(monero).unwrap();
let pics = amount.0;
assert_eq!(18446744073709551615, pics);
}
#[test]
fn parse_monero_overflows() {
let overflow_pics = "18446744.073709551616";
let error = Amount::parse_monero(overflow_pics).unwrap_err();
assert_eq!(
error.downcast_ref::<OverflowError>().unwrap(),
&OverflowError(overflow_pics.to_owned())
);
}
}

View file

@ -7,8 +7,8 @@ use reqwest::Url;
use std::time::Duration;
use tokio::time;
use xmr_btc::bitcoin::{
BlockHeight, BroadcastSignedTransaction, BuildTxLockPsbt, SignTxLock, TransactionBlockHeight,
TxLock, WatchForRawTransaction,
BlockHeight, BroadcastSignedTransaction, BuildTxLockPsbt, Network, SignTxLock,
TransactionBlockHeight, TxLock, WatchForRawTransaction,
};
#[derive(Debug)]
@ -162,3 +162,9 @@ impl TransactionBlockHeight for Wallet {
.expect("transient errors to be retried")
}
}
impl Network for Wallet {
fn get_network(&self) -> bitcoin::Network {
bitcoin::Network::Regtest
}
}