mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-27 14:09:48 +00:00
Stub out Scheduler in the Monero processor
This commit is contained in:
parent
e1ad897f7e
commit
a2d9aeaed7
6 changed files with 178 additions and 72 deletions
|
@ -130,8 +130,6 @@ impl Network for Monero {
|
||||||
const ESTIMATED_BLOCK_TIME_IN_SECONDS: usize = 120;
|
const ESTIMATED_BLOCK_TIME_IN_SECONDS: usize = 120;
|
||||||
const CONFIRMATIONS: usize = 10;
|
const CONFIRMATIONS: usize = 10;
|
||||||
|
|
||||||
const MAX_OUTPUTS: usize = 16;
|
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
const COST_TO_AGGREGATE: u64 = 0;
|
const COST_TO_AGGREGATE: u64 = 0;
|
||||||
|
|
||||||
|
@ -318,12 +316,4 @@ impl Network for Monero {
|
||||||
self.get_block(block).await.unwrap()
|
self.get_block(block).await.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UtxoNetwork for Monero {
|
|
||||||
// wallet2 will not create a transaction larger than 100kb, and Monero won't relay a transaction
|
|
||||||
// larger than 150kb. This fits within the 100kb mark
|
|
||||||
// Technically, it can be ~124, yet a small bit of buffer is appreciated
|
|
||||||
// TODO: Test creating a TX this big
|
|
||||||
const MAX_INPUTS: usize = 120;
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
static ALLOCATOR: zalloc::ZeroizingAlloc<std::alloc::System> =
|
static ALLOCATOR: zalloc::ZeroizingAlloc<std::alloc::System> =
|
||||||
zalloc::ZeroizingAlloc(std::alloc::System);
|
zalloc::ZeroizingAlloc(std::alloc::System);
|
||||||
|
|
||||||
use monero_wallet::rpc::Rpc as MRpc;
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
|
|
||||||
mod primitives;
|
mod primitives;
|
||||||
pub(crate) use crate::primitives::*;
|
pub(crate) use crate::primitives::*;
|
||||||
|
@ -15,18 +15,15 @@ mod key_gen;
|
||||||
use crate::key_gen::KeyGenParams;
|
use crate::key_gen::KeyGenParams;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
use rpc::Rpc;
|
use rpc::Rpc;
|
||||||
|
|
||||||
/*
|
|
||||||
mod scheduler;
|
mod scheduler;
|
||||||
use scheduler::Scheduler;
|
use scheduler::{Planner, Scheduler};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let db = bin::init();
|
let db = bin::init();
|
||||||
let feed = Rpc {
|
let feed = Rpc {
|
||||||
db: db.clone(),
|
|
||||||
rpc: loop {
|
rpc: loop {
|
||||||
match MRpc::new(bin::url()).await {
|
match SimpleRequestRpc::new(bin::url()).await {
|
||||||
Ok(rpc) => break rpc,
|
Ok(rpc) => break rpc,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("couldn't connect to the Monero node: {e:?}");
|
log::error!("couldn't connect to the Monero node: {e:?}");
|
||||||
|
@ -36,9 +33,11 @@ async fn main() {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
bin::main_loop::<_, KeyGenParams, Scheduler<_>, Rpc<bin::Db>>(db, feed.clone(), feed).await;
|
bin::main_loop::<_, KeyGenParams, _>(
|
||||||
|
db,
|
||||||
|
feed.clone(),
|
||||||
|
Scheduler::new(Planner(feed.clone())),
|
||||||
|
feed,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {}
|
|
||||||
|
|
|
@ -1,21 +1,17 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use zeroize::Zeroizing;
|
|
||||||
|
|
||||||
use ciphersuite::{Ciphersuite, Ed25519};
|
use ciphersuite::{Ciphersuite, Ed25519};
|
||||||
|
|
||||||
use monero_wallet::{
|
use monero_wallet::{
|
||||||
block::Block as MBlock, rpc::ScannableBlock as MScannableBlock, ViewPairError,
|
block::Block as MBlock, rpc::ScannableBlock as MScannableBlock, ScanError, GuaranteedScanner,
|
||||||
GuaranteedViewPair, ScanError, GuaranteedScanner,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use serai_client::networks::monero::Address;
|
use serai_client::networks::monero::Address;
|
||||||
|
|
||||||
use primitives::{ReceivedOutput, EventualityTracker};
|
use primitives::{ReceivedOutput, EventualityTracker};
|
||||||
use view_keys::view_key;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
EXTERNAL_SUBADDRESS, BRANCH_SUBADDRESS, CHANGE_SUBADDRESS, FORWARDED_SUBADDRESS, output::Output,
|
EXTERNAL_SUBADDRESS, BRANCH_SUBADDRESS, CHANGE_SUBADDRESS, FORWARDED_SUBADDRESS, view_pair,
|
||||||
transaction::Eventuality,
|
output::Output, transaction::Eventuality,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -45,17 +41,11 @@ impl primitives::Block for Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_for_outputs_unordered(&self, key: Self::Key) -> Vec<Self::Output> {
|
fn scan_for_outputs_unordered(&self, key: Self::Key) -> Vec<Self::Output> {
|
||||||
let view_pair = match GuaranteedViewPair::new(key.0, Zeroizing::new(*view_key::<Ed25519>(0))) {
|
let mut scanner = GuaranteedScanner::new(view_pair(key));
|
||||||
Ok(view_pair) => view_pair,
|
scanner.register_subaddress(EXTERNAL_SUBADDRESS);
|
||||||
Err(ViewPairError::TorsionedSpendKey) => {
|
scanner.register_subaddress(BRANCH_SUBADDRESS);
|
||||||
unreachable!("dalek_ff_group::EdwardsPoint had torsion")
|
scanner.register_subaddress(CHANGE_SUBADDRESS);
|
||||||
}
|
scanner.register_subaddress(FORWARDED_SUBADDRESS);
|
||||||
};
|
|
||||||
let mut scanner = GuaranteedScanner::new(view_pair);
|
|
||||||
scanner.register_subaddress(EXTERNAL_SUBADDRESS.unwrap());
|
|
||||||
scanner.register_subaddress(BRANCH_SUBADDRESS.unwrap());
|
|
||||||
scanner.register_subaddress(CHANGE_SUBADDRESS.unwrap());
|
|
||||||
scanner.register_subaddress(FORWARDED_SUBADDRESS.unwrap());
|
|
||||||
match scanner.scan(self.0.clone()) {
|
match scanner.scan(self.0.clone()) {
|
||||||
Ok(outputs) => outputs.not_additionally_locked().into_iter().map(Output).collect(),
|
Ok(outputs) => outputs.not_additionally_locked().into_iter().map(Output).collect(),
|
||||||
Err(ScanError::UnsupportedProtocol(version)) => {
|
Err(ScanError::UnsupportedProtocol(version)) => {
|
||||||
|
|
|
@ -1,10 +1,37 @@
|
||||||
use monero_wallet::address::SubaddressIndex;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
|
use ciphersuite::{Ciphersuite, Ed25519};
|
||||||
|
|
||||||
|
use monero_wallet::{address::SubaddressIndex, ViewPairError, GuaranteedViewPair};
|
||||||
|
|
||||||
|
use view_keys::view_key;
|
||||||
|
|
||||||
pub(crate) mod output;
|
pub(crate) mod output;
|
||||||
pub(crate) mod transaction;
|
pub(crate) mod transaction;
|
||||||
pub(crate) mod block;
|
pub(crate) mod block;
|
||||||
|
|
||||||
pub(crate) const EXTERNAL_SUBADDRESS: Option<SubaddressIndex> = SubaddressIndex::new(1, 0);
|
pub(crate) const EXTERNAL_SUBADDRESS: SubaddressIndex = match SubaddressIndex::new(1, 0) {
|
||||||
pub(crate) const BRANCH_SUBADDRESS: Option<SubaddressIndex> = SubaddressIndex::new(2, 0);
|
Some(index) => index,
|
||||||
pub(crate) const CHANGE_SUBADDRESS: Option<SubaddressIndex> = SubaddressIndex::new(2, 1);
|
None => panic!("SubaddressIndex for EXTERNAL_SUBADDRESS was None"),
|
||||||
pub(crate) const FORWARDED_SUBADDRESS: Option<SubaddressIndex> = SubaddressIndex::new(2, 2);
|
};
|
||||||
|
pub(crate) const BRANCH_SUBADDRESS: SubaddressIndex = match SubaddressIndex::new(2, 0) {
|
||||||
|
Some(index) => index,
|
||||||
|
None => panic!("SubaddressIndex for BRANCH_SUBADDRESS was None"),
|
||||||
|
};
|
||||||
|
pub(crate) const CHANGE_SUBADDRESS: SubaddressIndex = match SubaddressIndex::new(2, 1) {
|
||||||
|
Some(index) => index,
|
||||||
|
None => panic!("SubaddressIndex for CHANGE_SUBADDRESS was None"),
|
||||||
|
};
|
||||||
|
pub(crate) const FORWARDED_SUBADDRESS: SubaddressIndex = match SubaddressIndex::new(2, 2) {
|
||||||
|
Some(index) => index,
|
||||||
|
None => panic!("SubaddressIndex for FORWARDED_SUBADDRESS was None"),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) fn view_pair(key: <Ed25519 as Ciphersuite>::G) -> GuaranteedViewPair {
|
||||||
|
match GuaranteedViewPair::new(key.0, Zeroizing::new(*view_key::<Ed25519>(0))) {
|
||||||
|
Ok(view_pair) => view_pair,
|
||||||
|
Err(ViewPairError::TorsionedSpendKey) => {
|
||||||
|
unreachable!("dalek_ff_group::EdwardsPoint had torsion")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -46,16 +46,17 @@ impl ReceivedOutput<<Ed25519 as Ciphersuite>::G, Address> for Output {
|
||||||
type TransactionId = [u8; 32];
|
type TransactionId = [u8; 32];
|
||||||
|
|
||||||
fn kind(&self) -> OutputType {
|
fn kind(&self) -> OutputType {
|
||||||
if self.0.subaddress() == EXTERNAL_SUBADDRESS {
|
let subaddress = self.0.subaddress().unwrap();
|
||||||
|
if subaddress == EXTERNAL_SUBADDRESS {
|
||||||
return OutputType::External;
|
return OutputType::External;
|
||||||
}
|
}
|
||||||
if self.0.subaddress() == BRANCH_SUBADDRESS {
|
if subaddress == BRANCH_SUBADDRESS {
|
||||||
return OutputType::Branch;
|
return OutputType::Branch;
|
||||||
}
|
}
|
||||||
if self.0.subaddress() == CHANGE_SUBADDRESS {
|
if subaddress == CHANGE_SUBADDRESS {
|
||||||
return OutputType::Change;
|
return OutputType::Change;
|
||||||
}
|
}
|
||||||
if self.0.subaddress() == FORWARDED_SUBADDRESS {
|
if subaddress == FORWARDED_SUBADDRESS {
|
||||||
return OutputType::Forwarded;
|
return OutputType::Forwarded;
|
||||||
}
|
}
|
||||||
unreachable!("scanned output to unknown subaddress");
|
unreachable!("scanned output to unknown subaddress");
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/*
|
||||||
async fn make_signable_transaction(
|
async fn make_signable_transaction(
|
||||||
block_number: usize,
|
block_number: usize,
|
||||||
plan_id: &[u8; 32],
|
plan_id: &[u8; 32],
|
||||||
|
@ -136,10 +137,106 @@ match MSignableTransaction::new(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
use core::future::Future;
|
||||||
|
|
||||||
|
use ciphersuite::{Ciphersuite, Ed25519};
|
||||||
|
|
||||||
|
use monero_wallet::rpc::{FeeRate, RpcError};
|
||||||
|
|
||||||
|
use serai_client::{
|
||||||
|
primitives::{Coin, Amount},
|
||||||
|
networks::monero::Address,
|
||||||
|
};
|
||||||
|
|
||||||
|
use primitives::{OutputType, ReceivedOutput, Payment};
|
||||||
|
use scanner::{KeyFor, AddressFor, OutputFor, BlockFor};
|
||||||
|
use utxo_scheduler::{PlannedTransaction, TransactionPlanner};
|
||||||
|
|
||||||
|
use monero_wallet::address::Network;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
EXTERNAL_SUBADDRESS, BRANCH_SUBADDRESS, CHANGE_SUBADDRESS, FORWARDED_SUBADDRESS, view_pair,
|
||||||
|
output::Output,
|
||||||
|
transaction::{SignableTransaction, Eventuality},
|
||||||
|
rpc::Rpc,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn address_from_serai_key(key: <Ed25519 as Ciphersuite>::G, kind: OutputType) -> Address {
|
||||||
|
view_pair(key)
|
||||||
|
.address(
|
||||||
|
Network::Mainnet,
|
||||||
|
Some(match kind {
|
||||||
|
OutputType::External => EXTERNAL_SUBADDRESS,
|
||||||
|
OutputType::Branch => BRANCH_SUBADDRESS,
|
||||||
|
OutputType::Change => CHANGE_SUBADDRESS,
|
||||||
|
OutputType::Forwarded => FORWARDED_SUBADDRESS,
|
||||||
|
}),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.try_into()
|
||||||
|
.expect("created address which wasn't representable")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct Planner(pub(crate) Rpc);
|
||||||
|
impl TransactionPlanner<Rpc, ()> for Planner {
|
||||||
|
type EphemeralError = RpcError;
|
||||||
|
|
||||||
|
type FeeRate = FeeRate;
|
||||||
|
|
||||||
|
type SignableTransaction = SignableTransaction;
|
||||||
|
|
||||||
|
// wallet2 will not create a transaction larger than 100 KB, and Monero won't relay a transaction
|
||||||
|
// larger than 150 KB. This fits within the 100 KB mark to fit in and not poke the bear.
|
||||||
|
// Technically, it can be ~124, yet a small bit of buffer is appreciated
|
||||||
|
// TODO: Test creating a TX this big
|
||||||
|
const MAX_INPUTS: usize = 120;
|
||||||
|
const MAX_OUTPUTS: usize = 16;
|
||||||
|
|
||||||
|
fn fee_rate(block: &BlockFor<Rpc>, coin: Coin) -> Self::FeeRate {
|
||||||
|
assert_eq!(coin, Coin::Monero);
|
||||||
|
// TODO
|
||||||
|
todo!("TODO")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn branch_address(key: KeyFor<Rpc>) -> AddressFor<Rpc> {
|
||||||
|
address_from_serai_key(key, OutputType::Branch)
|
||||||
|
}
|
||||||
|
fn change_address(key: KeyFor<Rpc>) -> AddressFor<Rpc> {
|
||||||
|
address_from_serai_key(key, OutputType::Change)
|
||||||
|
}
|
||||||
|
fn forwarding_address(key: KeyFor<Rpc>) -> AddressFor<Rpc> {
|
||||||
|
address_from_serai_key(key, OutputType::Forwarded)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_fee(
|
||||||
|
fee_rate: Self::FeeRate,
|
||||||
|
inputs: Vec<OutputFor<Rpc>>,
|
||||||
|
payments: Vec<Payment<AddressFor<Rpc>>>,
|
||||||
|
change: Option<KeyFor<Rpc>>,
|
||||||
|
) -> Amount {
|
||||||
|
todo!("TODO")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn plan(
|
||||||
|
&self,
|
||||||
|
fee_rate: Self::FeeRate,
|
||||||
|
inputs: Vec<OutputFor<Rpc>>,
|
||||||
|
payments: Vec<Payment<AddressFor<Rpc>>>,
|
||||||
|
change: Option<KeyFor<Rpc>>,
|
||||||
|
) -> impl Send
|
||||||
|
+ Future<Output = Result<PlannedTransaction<Rpc, Self::SignableTransaction, ()>, RpcError>>
|
||||||
|
{
|
||||||
|
async move { todo!("TODO") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) type Scheduler = utxo_standard_scheduler::Scheduler<Rpc, Planner>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
use ciphersuite::{Ciphersuite, Secp256k1};
|
use ciphersuite::{Ciphersuite, Ed25519};
|
||||||
|
|
||||||
use bitcoin_serai::{
|
use bitcoin_serai::{
|
||||||
bitcoin::ScriptBuf,
|
bitcoin::ScriptBuf,
|
||||||
|
@ -163,8 +260,8 @@ use crate::{
|
||||||
rpc::Rpc,
|
rpc::Rpc,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn address_from_serai_key(key: <Secp256k1 as Ciphersuite>::G, kind: OutputType) -> Address {
|
fn address_from_serai_key(key: <Ed25519 as Ciphersuite>::G, kind: OutputType) -> Address {
|
||||||
let offset = <Secp256k1 as Ciphersuite>::G::GENERATOR * offsets_for_key(key)[&kind];
|
let offset = <Ed25519 as Ciphersuite>::G::GENERATOR * offsets_for_key(key)[&kind];
|
||||||
Address::new(
|
Address::new(
|
||||||
p2tr_script_buf(key + offset)
|
p2tr_script_buf(key + offset)
|
||||||
.expect("creating address from Serai key which wasn't properly tweaked"),
|
.expect("creating address from Serai key which wasn't properly tweaked"),
|
||||||
|
@ -174,17 +271,17 @@ fn address_from_serai_key(key: <Secp256k1 as Ciphersuite>::G, kind: OutputType)
|
||||||
|
|
||||||
fn signable_transaction<D: Db>(
|
fn signable_transaction<D: Db>(
|
||||||
fee_per_vbyte: u64,
|
fee_per_vbyte: u64,
|
||||||
inputs: Vec<OutputFor<Rpc<D>>>,
|
inputs: Vec<OutputFor<Rpc>>,
|
||||||
payments: Vec<Payment<AddressFor<Rpc<D>>>>,
|
payments: Vec<Payment<AddressFor<Rpc>>>,
|
||||||
change: Option<KeyFor<Rpc<D>>>,
|
change: Option<KeyFor<Rpc>>,
|
||||||
) -> Result<(SignableTransaction, BSignableTransaction), TransactionError> {
|
) -> Result<(SignableTransaction, BSignableTransaction), TransactionError> {
|
||||||
assert!(
|
assert!(
|
||||||
inputs.len() <
|
inputs.len() <
|
||||||
<Planner as TransactionPlanner<Rpc<D>, ()>>::MAX_INPUTS
|
<Planner as TransactionPlanner<Rpc, ()>>::MAX_INPUTS
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
(payments.len() + usize::from(u8::from(change.is_some()))) <
|
(payments.len() + usize::from(u8::from(change.is_some()))) <
|
||||||
<Planner as TransactionPlanner<Rpc<D>, ()>>::MAX_OUTPUTS
|
<Planner as TransactionPlanner<Rpc, ()>>::MAX_OUTPUTS
|
||||||
);
|
);
|
||||||
|
|
||||||
let inputs = inputs.into_iter().map(|input| input.output).collect::<Vec<_>>();
|
let inputs = inputs.into_iter().map(|input| input.output).collect::<Vec<_>>();
|
||||||
|
@ -194,7 +291,7 @@ fn signable_transaction<D: Db>(
|
||||||
.map(|payment| {
|
.map(|payment| {
|
||||||
(payment.address().clone(), {
|
(payment.address().clone(), {
|
||||||
let balance = payment.balance();
|
let balance = payment.balance();
|
||||||
assert_eq!(balance.coin, Coin::Bitcoin);
|
assert_eq!(balance.coin, Coin::Monero);
|
||||||
balance.amount.0
|
balance.amount.0
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -206,14 +303,14 @@ fn signable_transaction<D: Db>(
|
||||||
*/
|
*/
|
||||||
payments.push((
|
payments.push((
|
||||||
// The generator is even so this is valid
|
// The generator is even so this is valid
|
||||||
Address::new(p2tr_script_buf(<Secp256k1 as Ciphersuite>::G::GENERATOR).unwrap()).unwrap(),
|
Address::new(p2tr_script_buf(<Ed25519 as Ciphersuite>::G::GENERATOR).unwrap()).unwrap(),
|
||||||
// This uses the minimum output value allowed, as defined as a constant in bitcoin-serai
|
// This uses the minimum output value allowed, as defined as a constant in bitcoin-serai
|
||||||
// TODO: Add a test for this comparing to bitcoin's `minimal_non_dust`
|
// TODO: Add a test for this comparing to bitcoin's `minimal_non_dust`
|
||||||
bitcoin_serai::wallet::DUST,
|
bitcoin_serai::wallet::DUST,
|
||||||
));
|
));
|
||||||
|
|
||||||
let change = change
|
let change = change
|
||||||
.map(<Planner as TransactionPlanner<Rpc<D>, ()>>::change_address);
|
.map(<Planner as TransactionPlanner<Rpc, ()>>::change_address);
|
||||||
|
|
||||||
BSignableTransaction::new(
|
BSignableTransaction::new(
|
||||||
inputs.clone(),
|
inputs.clone(),
|
||||||
|
@ -231,12 +328,14 @@ fn signable_transaction<D: Db>(
|
||||||
|
|
||||||
pub(crate) struct Planner;
|
pub(crate) struct Planner;
|
||||||
impl TransactionPlanner<Rpc, ()> for Planner {
|
impl TransactionPlanner<Rpc, ()> for Planner {
|
||||||
|
type EphemeralError = RpcError;
|
||||||
|
|
||||||
type FeeRate = u64;
|
type FeeRate = u64;
|
||||||
|
|
||||||
type SignableTransaction = SignableTransaction;
|
type SignableTransaction = SignableTransaction;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Bitcoin has a max weight of 400,000 (MAX_STANDARD_TX_WEIGHT).
|
Monero has a max weight of 400,000 (MAX_STANDARD_TX_WEIGHT).
|
||||||
|
|
||||||
A non-SegWit TX will have 4 weight units per byte, leaving a max size of 100,000 bytes. While
|
A non-SegWit TX will have 4 weight units per byte, leaving a max size of 100,000 bytes. While
|
||||||
our inputs are entirely SegWit, such fine tuning is not necessary and could create issues in
|
our inputs are entirely SegWit, such fine tuning is not necessary and could create issues in
|
||||||
|
@ -255,27 +354,27 @@ impl TransactionPlanner<Rpc, ()> for Planner {
|
||||||
// to unstick any transactions which had too low of a fee.
|
// to unstick any transactions which had too low of a fee.
|
||||||
const MAX_OUTPUTS: usize = 519;
|
const MAX_OUTPUTS: usize = 519;
|
||||||
|
|
||||||
fn fee_rate(block: &BlockFor<Rpc<D>>, coin: Coin) -> Self::FeeRate {
|
fn fee_rate(block: &BlockFor<Rpc>, coin: Coin) -> Self::FeeRate {
|
||||||
assert_eq!(coin, Coin::Bitcoin);
|
assert_eq!(coin, Coin::Monero);
|
||||||
// TODO
|
// TODO
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn branch_address(key: KeyFor<Rpc<D>>) -> AddressFor<Rpc<D>> {
|
fn branch_address(key: KeyFor<Rpc>) -> AddressFor<Rpc> {
|
||||||
address_from_serai_key(key, OutputType::Branch)
|
address_from_serai_key(key, OutputType::Branch)
|
||||||
}
|
}
|
||||||
fn change_address(key: KeyFor<Rpc<D>>) -> AddressFor<Rpc<D>> {
|
fn change_address(key: KeyFor<Rpc>) -> AddressFor<Rpc> {
|
||||||
address_from_serai_key(key, OutputType::Change)
|
address_from_serai_key(key, OutputType::Change)
|
||||||
}
|
}
|
||||||
fn forwarding_address(key: KeyFor<Rpc<D>>) -> AddressFor<Rpc<D>> {
|
fn forwarding_address(key: KeyFor<Rpc>) -> AddressFor<Rpc> {
|
||||||
address_from_serai_key(key, OutputType::Forwarded)
|
address_from_serai_key(key, OutputType::Forwarded)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_fee(
|
fn calculate_fee(
|
||||||
fee_rate: Self::FeeRate,
|
fee_rate: Self::FeeRate,
|
||||||
inputs: Vec<OutputFor<Rpc<D>>>,
|
inputs: Vec<OutputFor<Rpc>>,
|
||||||
payments: Vec<Payment<AddressFor<Rpc<D>>>>,
|
payments: Vec<Payment<AddressFor<Rpc>>>,
|
||||||
change: Option<KeyFor<Rpc<D>>>,
|
change: Option<KeyFor<Rpc>>,
|
||||||
) -> Amount {
|
) -> Amount {
|
||||||
match signable_transaction::<D>(fee_rate, inputs, payments, change) {
|
match signable_transaction::<D>(fee_rate, inputs, payments, change) {
|
||||||
Ok(tx) => Amount(tx.1.needed_fee()),
|
Ok(tx) => Amount(tx.1.needed_fee()),
|
||||||
|
@ -294,10 +393,10 @@ impl TransactionPlanner<Rpc, ()> for Planner {
|
||||||
|
|
||||||
fn plan(
|
fn plan(
|
||||||
fee_rate: Self::FeeRate,
|
fee_rate: Self::FeeRate,
|
||||||
inputs: Vec<OutputFor<Rpc<D>>>,
|
inputs: Vec<OutputFor<Rpc>>,
|
||||||
payments: Vec<Payment<AddressFor<Rpc<D>>>>,
|
payments: Vec<Payment<AddressFor<Rpc>>>,
|
||||||
change: Option<KeyFor<Rpc<D>>>,
|
change: Option<KeyFor<Rpc>>,
|
||||||
) -> PlannedTransaction<Rpc<D>, Self::SignableTransaction, ()> {
|
) -> PlannedTransaction<Rpc, Self::SignableTransaction, ()> {
|
||||||
let key = inputs.first().unwrap().key();
|
let key = inputs.first().unwrap().key();
|
||||||
for input in &inputs {
|
for input in &inputs {
|
||||||
assert_eq!(key, input.key());
|
assert_eq!(key, input.key());
|
||||||
|
|
Loading…
Reference in a new issue