mirror of
https://github.com/serai-dex/serai.git
synced 2025-01-22 02:34:55 +00:00
Use const values for our traits where we can
This commit is contained in:
parent
b83ca7d666
commit
3617ed4eb7
12 changed files with 72 additions and 113 deletions
|
@ -57,25 +57,12 @@ impl<D: Digest<OutputSize = U64>, const WIDE: bool> Curve for Ed25519Internal<D,
|
|||
type G = dfg::EdwardsPoint;
|
||||
type T = &'static dfg::EdwardsBasepointTable;
|
||||
|
||||
fn id_len() -> u8 {
|
||||
u8::try_from(Self::id().len()).unwrap()
|
||||
}
|
||||
const ID: &'static [u8] = b"edwards25519";
|
||||
|
||||
fn id() -> &'static [u8] {
|
||||
b"edwards25519"
|
||||
}
|
||||
const GENERATOR: Self::G = dfg::ED25519_BASEPOINT_POINT;
|
||||
const GENERATOR_TABLE: Self::T = &dfg::ED25519_BASEPOINT_TABLE;
|
||||
|
||||
fn generator() -> Self::G {
|
||||
Self::G::generator()
|
||||
}
|
||||
|
||||
fn generator_table() -> Self::T {
|
||||
&dfg::ED25519_BASEPOINT_TABLE
|
||||
}
|
||||
|
||||
fn little_endian() -> bool {
|
||||
true
|
||||
}
|
||||
const LITTLE_ENDIAN: bool = true;
|
||||
|
||||
fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F {
|
||||
let mut seed = vec![0; 32];
|
||||
|
|
|
@ -41,7 +41,7 @@ fn generate_key_r1<R: RngCore + CryptoRng, C: Curve>(
|
|||
// Step 1: Generate t random values to form a polynomial with
|
||||
coefficients.push(C::F::random(&mut *rng));
|
||||
// Step 3: Generate public commitments
|
||||
commitments.push(C::generator_table() * coefficients[i]);
|
||||
commitments.push(C::GENERATOR_TABLE * coefficients[i]);
|
||||
// Serialize them for publication
|
||||
serialized.extend(&C::G_to_bytes(&commitments[i]));
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ fn generate_key_r1<R: RngCore + CryptoRng, C: Curve>(
|
|||
challenge::<C>(
|
||||
context,
|
||||
params.i(),
|
||||
&C::G_to_bytes(&(C::generator_table() * r)),
|
||||
&C::G_to_bytes(&(C::GENERATOR_TABLE * r)),
|
||||
&serialized
|
||||
)
|
||||
).serialize()
|
||||
|
@ -224,7 +224,7 @@ fn complete_r2<R: RngCore + CryptoRng, C: Curve>(
|
|||
res
|
||||
};
|
||||
|
||||
let mut batch = BatchVerifier::new(shares.len(), C::little_endian());
|
||||
let mut batch = BatchVerifier::new(shares.len(), C::LITTLE_ENDIAN);
|
||||
for (l, share) in &shares {
|
||||
if *l == params.i() {
|
||||
continue;
|
||||
|
@ -237,7 +237,7 @@ fn complete_r2<R: RngCore + CryptoRng, C: Curve>(
|
|||
// ensure that malleability isn't present is to use this n * t algorithm, which runs
|
||||
// per sender and not as an aggregate of all senders, which also enables blame
|
||||
let mut values = exponential(params.i, &commitments[l]);
|
||||
values.push((-*share, C::generator()));
|
||||
values.push((-*share, C::GENERATOR));
|
||||
batch.queue(rng, *l, values);
|
||||
}
|
||||
batch.verify_with_vartime_blame().map_err(|l| FrostError::InvalidCommitment(l))?;
|
||||
|
@ -254,9 +254,9 @@ fn complete_r2<R: RngCore + CryptoRng, C: Curve>(
|
|||
// Calculate each user's verification share
|
||||
let mut verification_shares = HashMap::new();
|
||||
for i in 1 ..= params.n() {
|
||||
verification_shares.insert(i, multiexp_vartime(exponential(i, &stripes), C::little_endian()));
|
||||
verification_shares.insert(i, multiexp_vartime(exponential(i, &stripes), C::LITTLE_ENDIAN));
|
||||
}
|
||||
debug_assert_eq!(C::generator_table() * secret_share, verification_shares[¶ms.i()]);
|
||||
debug_assert_eq!(C::GENERATOR_TABLE * secret_share, verification_shares[¶ms.i()]);
|
||||
|
||||
// TODO: Clear serialized and shares
|
||||
|
||||
|
|
|
@ -42,22 +42,19 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug {
|
|||
/// Precomputed table type
|
||||
type T: Mul<Self::F, Output = Self::G>;
|
||||
|
||||
/// Byte length of the curve ID
|
||||
// While C::id().len() is trivial, this bounds it to u8 for any proper Curve implementation
|
||||
fn id_len() -> u8;
|
||||
/// ID for this curve
|
||||
fn id() -> &'static [u8];
|
||||
const ID: &'static [u8];
|
||||
|
||||
/// Generator for the group
|
||||
// While group does provide this in its API, Jubjub users will want to use a custom basepoint
|
||||
fn generator() -> Self::G;
|
||||
// While group does provide this in its API, privacy coins will want to use a custom basepoint
|
||||
const GENERATOR: Self::G;
|
||||
|
||||
/// Table for the generator for the group
|
||||
/// If there isn't a precomputed table available, the generator itself should be used
|
||||
fn generator_table() -> Self::T;
|
||||
const GENERATOR_TABLE: Self::T;
|
||||
|
||||
/// If little endian is used for the scalar field's Repr
|
||||
fn little_endian() -> bool;
|
||||
const LITTLE_ENDIAN: bool;
|
||||
|
||||
/// Securely generate a random nonce. H4 from the IETF draft
|
||||
fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F;
|
||||
|
@ -298,12 +295,12 @@ impl<C: Curve> MultisigKeys<C> {
|
|||
let offset_share = offset * C::F::from(included.len().try_into().unwrap()).invert().unwrap();
|
||||
|
||||
Ok(MultisigView {
|
||||
group_key: self.group_key + (C::generator_table() * offset),
|
||||
group_key: self.group_key + (C::GENERATOR_TABLE * offset),
|
||||
secret_share: secret_share + offset_share,
|
||||
verification_shares: self.verification_shares.iter().map(
|
||||
|(l, share)| (
|
||||
*l,
|
||||
(*share * lagrange::<C::F>(*l, &included)) + (C::generator_table() * offset_share)
|
||||
(*share * lagrange::<C::F>(*l, &included)) + (C::GENERATOR_TABLE * offset_share)
|
||||
)
|
||||
).collect(),
|
||||
included: included.to_vec(),
|
||||
|
@ -311,15 +308,13 @@ impl<C: Curve> MultisigKeys<C> {
|
|||
}
|
||||
|
||||
pub fn serialized_len(n: u16) -> usize {
|
||||
1 + usize::from(C::id_len()) + (3 * 2) + C::F_len() + C::G_len() + (usize::from(n) * C::G_len())
|
||||
8 + C::ID.len() + (3 * 2) + C::F_len() + C::G_len() + (usize::from(n) * C::G_len())
|
||||
}
|
||||
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
let mut serialized = Vec::with_capacity(
|
||||
1 + usize::from(C::id_len()) + MultisigKeys::<C>::serialized_len(self.params.n)
|
||||
);
|
||||
serialized.push(C::id_len());
|
||||
serialized.extend(C::id());
|
||||
let mut serialized = Vec::with_capacity(MultisigKeys::<C>::serialized_len(self.params.n));
|
||||
serialized.extend(u64::try_from(C::ID.len()).unwrap().to_be_bytes());
|
||||
serialized.extend(C::ID);
|
||||
serialized.extend(&self.params.t.to_be_bytes());
|
||||
serialized.extend(&self.params.n.to_be_bytes());
|
||||
serialized.extend(&self.params.i.to_be_bytes());
|
||||
|
@ -328,34 +323,28 @@ impl<C: Curve> MultisigKeys<C> {
|
|||
for l in 1 ..= self.params.n.into() {
|
||||
serialized.extend(&C::G_to_bytes(&self.verification_shares[&l]));
|
||||
}
|
||||
|
||||
serialized
|
||||
}
|
||||
|
||||
pub fn deserialize(serialized: &[u8]) -> Result<MultisigKeys<C>, FrostError> {
|
||||
if serialized.len() < 1 {
|
||||
Err(FrostError::InternalError("MultisigKeys serialization is empty".to_string()))?;
|
||||
let mut start = u64::try_from(C::ID.len()).unwrap().to_be_bytes().to_vec();
|
||||
start.extend(C::ID);
|
||||
let mut cursor = start.len();
|
||||
|
||||
if serialized.len() < (cursor + 4) {
|
||||
Err(
|
||||
FrostError::InternalError(
|
||||
"MultisigKeys serialization is missing its curve/participant quantities".to_string()
|
||||
)
|
||||
)?;
|
||||
}
|
||||
|
||||
let id_len: usize = serialized[0].into();
|
||||
let mut cursor = 1;
|
||||
|
||||
if serialized.len() < (cursor + id_len) {
|
||||
Err(FrostError::InternalError("ID wasn't included".to_string()))?;
|
||||
}
|
||||
|
||||
if C::id() != &serialized[cursor .. (cursor + id_len)] {
|
||||
if &start != &serialized[.. cursor] {
|
||||
Err(
|
||||
FrostError::InternalError(
|
||||
"curve is distinct between serialization and deserialization".to_string()
|
||||
)
|
||||
)?;
|
||||
}
|
||||
cursor += id_len;
|
||||
|
||||
if serialized.len() < (cursor + 4) {
|
||||
Err(FrostError::InternalError("participant quantities weren't included".to_string()))?;
|
||||
}
|
||||
|
||||
let t = u16::from_be_bytes(serialized[cursor .. (cursor + 2)].try_into().unwrap());
|
||||
cursor += 2;
|
||||
|
|
|
@ -28,7 +28,7 @@ pub(crate) fn sign<C: Curve>(
|
|||
challenge: C::F
|
||||
) -> SchnorrSignature<C> {
|
||||
SchnorrSignature {
|
||||
R: C::generator_table() * nonce,
|
||||
R: C::GENERATOR_TABLE * nonce,
|
||||
s: nonce + (private_key * challenge)
|
||||
}
|
||||
}
|
||||
|
@ -38,15 +38,15 @@ pub(crate) fn verify<C: Curve>(
|
|||
challenge: C::F,
|
||||
signature: &SchnorrSignature<C>
|
||||
) -> bool {
|
||||
(C::generator_table() * signature.s) == (signature.R + (public_key * challenge))
|
||||
(C::GENERATOR_TABLE * signature.s) == (signature.R + (public_key * challenge))
|
||||
}
|
||||
|
||||
pub(crate) fn batch_verify<C: Curve, R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
triplets: &[(u16, C::G, C::F, SchnorrSignature<C>)]
|
||||
) -> Result<(), u16> {
|
||||
let mut values = [(C::F::one(), C::generator()); 3];
|
||||
let mut batch = BatchVerifier::new(triplets.len(), C::little_endian());
|
||||
let mut values = [(C::F::one(), C::GENERATOR); 3];
|
||||
let mut batch = BatchVerifier::new(triplets.len(), C::LITTLE_ENDIAN);
|
||||
for triple in triplets {
|
||||
// s = r + ca
|
||||
// sG == R + cA
|
||||
|
|
|
@ -84,7 +84,7 @@ fn preprocess<R: RngCore + CryptoRng, C: Curve, A: Algorithm<C>>(
|
|||
C::random_nonce(params.view().secret_share(), &mut *rng),
|
||||
C::random_nonce(params.view().secret_share(), &mut *rng)
|
||||
];
|
||||
let commitments = [C::generator_table() * nonces[0], C::generator_table() * nonces[1]];
|
||||
let commitments = [C::GENERATOR_TABLE * nonces[0], C::GENERATOR_TABLE * nonces[1]];
|
||||
let mut serialized = C::G_to_bytes(&commitments[0]);
|
||||
serialized.extend(&C::G_to_bytes(&commitments[1]));
|
||||
|
||||
|
|
|
@ -82,25 +82,12 @@ impl Curve for P256 {
|
|||
type G = ProjectivePoint;
|
||||
type T = ProjectivePoint;
|
||||
|
||||
fn id_len() -> u8 {
|
||||
u8::try_from(Self::id().len()).unwrap()
|
||||
}
|
||||
const ID: &'static [u8] = b"P-256";
|
||||
|
||||
fn id() -> &'static [u8] {
|
||||
b"P-256"
|
||||
}
|
||||
const GENERATOR: Self::G = Self::G::GENERATOR;
|
||||
const GENERATOR_TABLE: Self::G = Self::G::GENERATOR;
|
||||
|
||||
fn generator() -> Self::G {
|
||||
Self::G::GENERATOR
|
||||
}
|
||||
|
||||
fn generator_table() -> Self::T {
|
||||
Self::G::GENERATOR
|
||||
}
|
||||
|
||||
fn little_endian() -> bool {
|
||||
false
|
||||
}
|
||||
const LITTLE_ENDIAN: bool = false;
|
||||
|
||||
fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F {
|
||||
let mut seed = vec![0; 32];
|
||||
|
|
|
@ -113,7 +113,7 @@ pub fn recover<C: Curve>(keys: &HashMap<u16, MultisigKeys<C>>) -> C::F {
|
|||
C::F::zero(),
|
||||
|accum, (i, keys)| accum + (keys.secret_share() * lagrange::<C::F>(*i, &included))
|
||||
);
|
||||
assert_eq!(C::generator_table() * group_private, first.group_key(), "failed to recover keys");
|
||||
assert_eq!(C::GENERATOR_TABLE * group_private, first.group_key(), "failed to recover keys");
|
||||
group_private
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ pub(crate) fn core_sign<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
|
|||
let challenge = C::F::random(rng); // Doesn't bother to craft an HRAM
|
||||
assert!(
|
||||
schnorr::verify::<C>(
|
||||
C::generator_table() * private_key,
|
||||
C::GENERATOR_TABLE * private_key,
|
||||
challenge,
|
||||
&schnorr::sign(private_key, nonce, challenge)
|
||||
)
|
||||
|
@ -28,9 +28,9 @@ pub(crate) fn core_sign<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
|
|||
pub(crate) fn core_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
|
||||
assert!(
|
||||
!schnorr::verify::<C>(
|
||||
C::generator_table() * C::F::random(&mut *rng),
|
||||
C::GENERATOR_TABLE * C::F::random(&mut *rng),
|
||||
C::F::random(rng),
|
||||
&SchnorrSignature { R: C::generator_table() * C::F::zero(), s: C::F::zero() }
|
||||
&SchnorrSignature { R: C::GENERATOR_TABLE * C::F::zero(), s: C::F::zero() }
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ pub(crate) fn core_batch_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
|
|||
|
||||
// Batch verify
|
||||
let triplets = (0 .. 5).map(
|
||||
|i| (u16::try_from(i + 1).unwrap(), C::generator_table() * keys[i], challenges[i], sigs[i])
|
||||
|i| (u16::try_from(i + 1).unwrap(), C::GENERATOR_TABLE * keys[i], challenges[i], sigs[i])
|
||||
).collect::<Vec<_>>();
|
||||
schnorr::batch_verify(rng, &triplets).unwrap();
|
||||
|
||||
|
@ -113,7 +113,7 @@ fn sign_with_offset<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
|
|||
for i in 1 ..= u16::try_from(keys.len()).unwrap() {
|
||||
keys.insert(i, Rc::new(keys[&i].offset(offset)));
|
||||
}
|
||||
let offset_key = group_key + (C::generator_table() * offset);
|
||||
let offset_key = group_key + (C::GENERATOR_TABLE * offset);
|
||||
|
||||
sign_core(rng, offset_key, &keys);
|
||||
}
|
||||
|
|
|
@ -26,14 +26,14 @@ fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, Multisi
|
|||
|secret| C::F_from_slice(&hex::decode(secret).unwrap()).unwrap()
|
||||
).collect::<Vec<_>>();
|
||||
let verification_shares = shares.iter().map(
|
||||
|secret| C::generator() * secret
|
||||
|secret| C::GENERATOR * secret
|
||||
).collect::<Vec<_>>();
|
||||
|
||||
let mut keys = HashMap::new();
|
||||
for i in 1 ..= u16::try_from(shares.len()).unwrap() {
|
||||
let mut serialized = vec![];
|
||||
serialized.push(C::id_len());
|
||||
serialized.extend(C::id());
|
||||
serialized.extend(u64::try_from(C::ID.len()).unwrap().to_be_bytes());
|
||||
serialized.extend(C::ID);
|
||||
serialized.extend(vectors.threshold.to_be_bytes());
|
||||
serialized.extend(u16::try_from(shares.len()).unwrap().to_be_bytes());
|
||||
serialized.extend(i.to_be_bytes());
|
||||
|
@ -59,7 +59,7 @@ pub fn vectors<C: Curve, H: Hram<C>>(vectors: Vectors) {
|
|||
let keys = vectors_to_multisig_keys::<C>(&vectors);
|
||||
let group_key = C::G_from_slice(&hex::decode(vectors.group_key).unwrap()).unwrap();
|
||||
assert_eq!(
|
||||
C::generator() * C::F_from_slice(&hex::decode(vectors.group_secret).unwrap()).unwrap(),
|
||||
C::GENERATOR * C::F_from_slice(&hex::decode(vectors.group_secret).unwrap()).unwrap(),
|
||||
group_key
|
||||
);
|
||||
assert_eq!(
|
||||
|
@ -87,8 +87,8 @@ pub fn vectors<C: Curve, H: Hram<C>>(vectors: Vectors) {
|
|||
C::F_from_slice(&hex::decode(vectors.nonces[c][1]).unwrap()).unwrap()
|
||||
];
|
||||
|
||||
let mut serialized = C::G_to_bytes(&(C::generator() * nonces[0]));
|
||||
serialized.extend(&C::G_to_bytes(&(C::generator() * nonces[1])));
|
||||
let mut serialized = C::G_to_bytes(&(C::GENERATOR * nonces[0]));
|
||||
serialized.extend(&C::G_to_bytes(&(C::GENERATOR * nonces[1])));
|
||||
|
||||
machine.unsafe_override_preprocess(
|
||||
PreprocessPackage { nonces, serialized: serialized.clone() }
|
||||
|
|
|
@ -58,7 +58,7 @@ impl Monero {
|
|||
pub fn new(url: String) -> Monero {
|
||||
Monero {
|
||||
rpc: Rpc::new(url),
|
||||
view: dfg::Scalar::from_hash(view_key::<Monero>(0)).0
|
||||
view: *view_key::<Monero>(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,16 +73,16 @@ impl Coin for Monero {
|
|||
|
||||
type Address = Address;
|
||||
|
||||
fn id() -> &'static [u8] { b"Monero" }
|
||||
fn confirmations() -> usize { 10 }
|
||||
const ID: &'static [u8] = b"Monero";
|
||||
const CONFIRMATIONS: usize = 10;
|
||||
// Testnet TX bb4d188a4c571f2f0de70dca9d475abc19078c10ffa8def26dd4f63ce1bcfd79 uses 146 inputs
|
||||
// while using less than 100kb of space, albeit with just 2 outputs (though outputs share a BP)
|
||||
// The TX size limit is half the contextual median block weight, where said weight is >= 300,000
|
||||
// This means any TX which fits into 150kb will be accepted by Monero
|
||||
// 128, even with 16 outputs, should fit into 100kb. Further efficiency by 192 may be viable
|
||||
// TODO: Get hard numbers and tune
|
||||
fn max_inputs() -> usize { 128 }
|
||||
fn max_outputs() -> usize { 16 }
|
||||
const MAX_INPUTS: usize = 128;
|
||||
const MAX_OUTPUTS: usize = 16;
|
||||
|
||||
async fn get_height(&self) -> Result<usize, CoinError> {
|
||||
self.rpc.get_height().await.map_err(|_| CoinError::ConnectionError)
|
||||
|
|
|
@ -4,8 +4,6 @@ use async_trait::async_trait;
|
|||
use thiserror::Error;
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use blake2::{digest::{Digest, Update}, Blake2b512};
|
||||
|
||||
use frost::{Curve, MultisigKeys};
|
||||
|
||||
mod coins;
|
||||
|
@ -40,10 +38,10 @@ pub trait Coin {
|
|||
|
||||
type Address: Send;
|
||||
|
||||
fn id() -> &'static [u8];
|
||||
fn confirmations() -> usize;
|
||||
fn max_inputs() -> usize;
|
||||
fn max_outputs() -> usize;
|
||||
const ID: &'static [u8];
|
||||
const CONFIRMATIONS: usize;
|
||||
const MAX_INPUTS: usize;
|
||||
const MAX_OUTPUTS: usize;
|
||||
|
||||
async fn get_height(&self) -> Result<usize, CoinError>;
|
||||
async fn get_block(&self, height: usize) -> Result<Self::Block, CoinError>;
|
||||
|
@ -70,11 +68,9 @@ pub trait Coin {
|
|||
) -> Result<(Vec<u8>, Vec<<Self::Output as Output>::Id>), CoinError>;
|
||||
}
|
||||
|
||||
// Generate a view key for a given chain in a globally consistent manner regardless of the current
|
||||
// group key
|
||||
// Generate a static view key for a given chain in a globally consistent manner
|
||||
// Doesn't consider the current group key to increase the simplicity of verifying Serai's status
|
||||
// Takes an index, k, for more modern privacy protocols which use multiple view keys
|
||||
// Doesn't run Curve::hash_to_F, instead returning the hash object, due to hash_to_F being a FROST
|
||||
// definition instead of a wide reduction from a hash object
|
||||
pub fn view_key<C: Coin>(k: u64) -> Blake2b512 {
|
||||
Blake2b512::new().chain(b"Serai DEX View Key").chain(C::id()).chain(k.to_le_bytes())
|
||||
pub fn view_key<C: Coin>(k: u64) -> <C::Curve as Curve>::F {
|
||||
C::Curve::hash_to_F(b"Serai DEX View Key", &[C::ID, &k.to_le_bytes()].concat())
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ impl<C: Curve> WalletKeys<C> {
|
|||
}
|
||||
|
||||
// Bind this key to a specific network by applying an additive offset
|
||||
// While it would be fine to just C::id(), including the group key creates distinct
|
||||
// While it would be fine to just C::ID, including the group key creates distinct
|
||||
// offsets instead of static offsets. Under a statically offset system, a BTC key could
|
||||
// have X subtracted to find the potential group key, and then have Y added to find the
|
||||
// potential ETH group key. While this shouldn't be an issue, as this isn't a private
|
||||
|
@ -27,7 +27,7 @@ impl<C: Curve> WalletKeys<C> {
|
|||
const DST: &[u8] = b"Serai Processor Wallet Chain Bind";
|
||||
let mut transcript = DigestTranscript::<blake2::Blake2b512>::new(DST);
|
||||
transcript.append_message(b"chain", chain);
|
||||
transcript.append_message(b"curve", C::id());
|
||||
transcript.append_message(b"curve", C::ID);
|
||||
transcript.append_message(b"group_key", &C::G_to_bytes(&self.keys.group_key()));
|
||||
self.keys.offset(C::hash_to_F(DST, &transcript.challenge(b"offset")))
|
||||
}
|
||||
|
@ -73,11 +73,11 @@ impl<C: Coin> Wallet<C> {
|
|||
|
||||
pub fn add_keys(&mut self, keys: &WalletKeys<C::Curve>) {
|
||||
// Doesn't use +1 as this is height, not block index, and poll moves by block index
|
||||
self.pending.push((self.acknowledged_height(keys.creation_height), keys.bind(C::id())));
|
||||
self.pending.push((self.acknowledged_height(keys.creation_height), keys.bind(C::ID)));
|
||||
}
|
||||
|
||||
pub async fn poll(&mut self) -> Result<(), CoinError> {
|
||||
let confirmed_height = self.coin.get_height().await? - C::confirmations();
|
||||
let confirmed_height = self.coin.get_height().await? - C::CONFIRMATIONS;
|
||||
for height in self.scanned_height() .. confirmed_height {
|
||||
// If any keys activated at this height, shift them over
|
||||
{
|
||||
|
@ -114,7 +114,7 @@ impl<C: Coin> Wallet<C> {
|
|||
|
||||
let acknowledged_height = self.acknowledged_height(canonical);
|
||||
|
||||
// TODO: Log schedule outputs when max_outputs is low
|
||||
// TODO: Log schedule outputs when MAX_OUTPUTS is low
|
||||
// Payments is the first set of TXs in the schedule
|
||||
// As each payment re-appears, let mut payments = schedule[payment] where the only input is
|
||||
// the source payment
|
||||
|
@ -129,7 +129,7 @@ impl<C: Coin> Wallet<C> {
|
|||
|
||||
while outputs.len() != 0 {
|
||||
// Select the maximum amount of outputs possible
|
||||
let mut inputs = &outputs[0 .. C::max_inputs().min(outputs.len())];
|
||||
let mut inputs = &outputs[0 .. C::MAX_INPUTS.min(outputs.len())];
|
||||
|
||||
// Calculate their sum value, minus the fee needed to spend them
|
||||
let mut sum = inputs.iter().map(|input| input.amount()).sum::<u64>();
|
||||
|
|
Loading…
Reference in a new issue