Skip to content

Commit 4d61364

Browse files
authored
Update Javascript wallet bindings, replace wallet approach with the basic transaction building (#146)
- make a singVotes as a free function, not a method of the Wallet type - remove Wallet type and Wallet usage from the Javascript bindings - implement a simple TransactionBuilder type with the only transaction building functionality. - refactoring
2 parents 8cab8bc + 5339406 commit 4d61364

File tree

22 files changed

+352
-335
lines changed

22 files changed

+352
-335
lines changed

src/catalyst-toolbox/catalyst-toolbox/src/recovery/tally.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,8 @@ impl FragmentReplayer {
517517
let builder_help = wallet
518518
.new_transaction(tx.total_input().unwrap(), 0)
519519
.unwrap();
520-
let mut builder = TransactionBuilder::new(&self.settings, vote_cast, tx.valid_until());
520+
let mut builder =
521+
TransactionBuilder::new(self.settings.clone(), vote_cast, tx.valid_until());
521522
builder.add_input(builder_help.input(), builder_help.witness_builder());
522523
let res = Fragment::VoteCast(builder.finalize_tx(()).unwrap());
523524

@@ -567,7 +568,7 @@ impl FragmentReplayer {
567568
let builder_help = wallet
568569
.new_transaction(tx.total_input().unwrap(), 0)
569570
.unwrap();
570-
let mut builder = TransactionBuilder::new(&self.settings, NoExtra, tx.valid_until());
571+
let mut builder = TransactionBuilder::new(self.settings.clone(), NoExtra, tx.valid_until());
571572
builder.add_input(builder_help.input(), builder_help.witness_builder());
572573
builder.add_output(Output::from_address(output_address, output.value));
573574
let res = Fragment::Transaction(builder.finalize_tx(()).unwrap());

src/chain-libs/chain-impl-mockchain/src/accounting/account/mod.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,10 @@ pub enum LedgerError {
3131
AlreadyExists,
3232
#[error("Removed account is not empty")]
3333
NonZero,
34-
#[error("Spending credential invalid, expected {} got {} in lane {}", .expected.unlaned_counter(), .actual.unlaned_counter(), .actual.lane())]
35-
SpendingCredentialInvalid {
36-
expected: SpendingCounter,
37-
actual: SpendingCounter,
38-
},
3934
#[error("Value calculation failed")]
4035
ValueError(#[from] ValueError),
36+
#[error(transparent)]
37+
SpendingCounterError(#[from] spending::Error),
4138
}
4239

4340
impl From<UpdateError<LedgerError>> for LedgerError {

src/chain-libs/chain-impl-mockchain/src/accounting/account/spending.rs

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
//! Spending strategies
2-
use super::LedgerError;
2+
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
3+
pub enum Error {
4+
#[error("Spending credential invalid, expected {} got {} in lane {}", .expected.unlaned_counter(), .actual.unlaned_counter(), .actual.lane())]
5+
SpendingCredentialInvalid {
6+
expected: SpendingCounter,
7+
actual: SpendingCounter,
8+
},
9+
#[error("Invalid lane: {0} or counter: {1}, expected lane < (1 << LANES_BITS), counter < (1 << UNLANES_BITS)")]
10+
InvalidLaneOrCounter(usize, u32),
11+
}
312

413
/// Simple strategy to spend from multiple increasing counters
514
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -15,7 +24,7 @@ const LANES_BITS: usize = 3;
1524
const UNLANES_BITS: usize = 32 - LANES_BITS;
1625

1726
impl SpendingCounterIncreasing {
18-
/// number of parallel lanes of increasing counters
27+
/// number of parallel lanes of increasing counters, equals to 8
1928
pub const LANES: usize = 1 << LANES_BITS;
2029

2130
pub fn new_from_counter(set: SpendingCounter) -> Self {
@@ -46,14 +55,14 @@ impl SpendingCounterIncreasing {
4655
}
4756

4857
/// try to match the lane of the counter in argument, if it doesn't match
49-
/// a ledger error reported.
58+
/// an error reported.
5059
///
5160
/// If the counter match succesfully, then the counter at this lane is incremented by one.
52-
pub fn next_verify(&mut self, counter: SpendingCounter) -> Result<(), LedgerError> {
61+
pub fn next_verify(&mut self, counter: SpendingCounter) -> Result<(), Error> {
5362
let actual_counter = self.nexts[counter.lane()];
5463

5564
if actual_counter != counter {
56-
Err(LedgerError::SpendingCredentialInvalid {
65+
Err(Error::SpendingCredentialInvalid {
5766
expected: actual_counter,
5867
actual: counter,
5968
})
@@ -78,7 +87,7 @@ impl Default for SpendingCounterIncreasing {
7887
fn default() -> Self {
7988
let mut nexts = Vec::new();
8089
for i in 0..Self::LANES {
81-
nexts.push(SpendingCounter::new(i, 0));
90+
nexts.push(SpendingCounter::new(i, 0).unwrap());
8291
}
8392
SpendingCounterIncreasing { nexts }
8493
}
@@ -115,10 +124,14 @@ impl SpendingCounter {
115124
self.0 & Self::UNLANED_MASK
116125
}
117126

118-
pub fn new(lane: usize, counter: u32) -> Self {
119-
assert!(lane < (1 << LANES_BITS));
120-
assert!(counter < (1 << UNLANES_BITS));
121-
SpendingCounter((lane << UNLANES_BITS) as u32 | (counter & Self::UNLANED_MASK))
127+
pub fn new(lane: usize, counter: u32) -> Result<Self, Error> {
128+
if lane < (1 << LANES_BITS) || counter < (1 << UNLANES_BITS) {
129+
Ok(SpendingCounter(
130+
(lane << UNLANES_BITS) as u32 | (counter & Self::UNLANED_MASK),
131+
))
132+
} else {
133+
Err(Error::InvalidLaneOrCounter(lane, counter))
134+
}
122135
}
123136

124137
pub fn zero() -> Self {
@@ -175,18 +188,17 @@ mod tests {
175188
}
176189

177190
#[test]
178-
#[should_panic]
179191
fn new_invalid_spending_counter() {
180192
let lane: usize = (1 << LANES_BITS) + 1;
181193
let counter: u32 = 1 << UNLANES_BITS;
182-
SpendingCounter::new(lane, counter);
194+
assert!(SpendingCounter::new(lane, counter).is_err());
183195
}
184196

185197
#[quickcheck_macros::quickcheck]
186198
fn new_spending_counter(mut lane: usize, mut counter: u32) {
187199
lane %= 1 << LANES_BITS;
188200
counter %= 1 << UNLANES_BITS;
189-
let sc = SpendingCounter::new(lane, counter);
201+
let sc = SpendingCounter::new(lane, counter).unwrap();
190202

191203
assert_eq!(lane, sc.lane());
192204
assert_eq!(counter, sc.unlaned_counter());
@@ -220,14 +232,14 @@ mod tests {
220232
#[should_panic]
221233
#[cfg(debug_assertions)]
222234
fn increment_counter_overflow_debug() {
223-
let _ = SpendingCounter::new(8, u32::MAX).increment();
235+
let _ = SpendingCounter::new(8, u32::MAX).unwrap().increment();
224236
}
225237

226238
#[test]
227239
#[should_panic]
228240
#[cfg(debug_assertions)]
229241
pub fn increment_nth_overflow_debug() {
230-
let _ = SpendingCounter::new(0, 1).increment_nth(u32::MAX);
242+
let _ = SpendingCounter::new(0, 1).unwrap().increment_nth(u32::MAX);
231243
}
232244

233245
#[quickcheck_macros::quickcheck]
@@ -248,7 +260,10 @@ mod tests {
248260

249261
#[test]
250262
pub fn spending_counters_incorrect_order() {
251-
let counters = vec![SpendingCounter::new(1, 0), SpendingCounter::new(0, 0)];
263+
let counters = vec![
264+
SpendingCounter::new(1, 0).unwrap(),
265+
SpendingCounter::new(0, 0).unwrap(),
266+
];
252267
assert!(SpendingCounterIncreasing::new_from_counters(counters).is_none());
253268
}
254269

@@ -274,15 +289,14 @@ mod tests {
274289
#[test]
275290
pub fn spending_counter_increasing_wrong_counter() {
276291
let mut sc_increasing = SpendingCounterIncreasing::default();
277-
let incorrect_sc = SpendingCounter::new(0, 100);
292+
let incorrect_sc = SpendingCounter::new(0, 100).unwrap();
278293
assert!(sc_increasing.next_verify(incorrect_sc).is_err());
279294
}
280295

281296
#[test]
282-
#[should_panic]
283297
pub fn spending_counter_increasing_wrong_lane() {
284298
let mut sc_increasing = SpendingCounterIncreasing::default();
285-
let incorrect_sc = SpendingCounter::new(SpendingCounterIncreasing::LANES, 1);
299+
let incorrect_sc = SpendingCounter::new(SpendingCounterIncreasing::LANES, 1).unwrap();
286300
assert!(sc_increasing.next_verify(incorrect_sc).is_err());
287301
}
288302

src/chain-libs/chain-impl-mockchain/src/ledger/tests/transaction_tests.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,12 @@ pub fn duplicated_account_transaction() {
130130
match result {
131131
Err(err) => panic!("first transaction should be succesful but {}", err),
132132
Ok(_) => match test_ledger.apply_transaction(fragment2, BlockDate::first()) {
133-
Err(ledger::Error::Account(
134-
crate::account::LedgerError::SpendingCredentialInvalid { expected, actual },
135-
)) => {
133+
Err(ledger::Error::Account(crate::account::LedgerError::SpendingCounterError(
134+
crate::accounting::account::spending::Error::SpendingCredentialInvalid {
135+
expected,
136+
actual,
137+
},
138+
))) => {
136139
assert_eq!(expected, SpendingCounter::zero().increment());
137140
assert_eq!(actual, SpendingCounter::zero());
138141
}

src/chain-libs/chain-impl-mockchain/src/testing/data/address.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
account::Identifier,
3-
account::SpendingCounter,
3+
account::{LedgerError, SpendingCounter},
44
accounting::account::SpendingCounterIncreasing,
55
chaintypes::HeaderId,
66
key::EitherEd25519SecretKey,
@@ -190,7 +190,9 @@ impl AddressData {
190190

191191
pub fn confirm_transaction_at_lane(&mut self, lane: usize) -> Result<(), Error> {
192192
let sc = self.spending_counter_at_lane(lane)?;
193-
self.spending_counter.next_verify(sc).map_err(Into::into)
193+
self.spending_counter
194+
.next_verify(sc)
195+
.map_err(|e| LedgerError::SpendingCounterError(e).into())
194196
}
195197

196198
pub fn spending_counter_at_lane(&self, lane: usize) -> Result<SpendingCounter, Error> {

src/chain-wallet-libs/bindings/wallet-core/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
pub mod c;
22
mod error;
3+
mod tx_builder;
34
mod vote;
45
mod wallet;
56

67
pub use self::{
78
error::{Error, ErrorCode, ErrorKind, Result},
9+
tx_builder::TxBuilder,
810
vote::Proposal,
911
wallet::Wallet,
1012
};
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use chain_crypto::SecretKey;
2+
use chain_impl_mockchain::{
3+
account::SpendingCounter,
4+
fragment::Fragment,
5+
header::BlockDate,
6+
transaction::{Input, Payload, Transaction},
7+
};
8+
use wallet::{EitherAccount, Settings};
9+
10+
use crate::Error;
11+
12+
pub struct TxBuilder<P: Payload> {
13+
builder: wallet::TransactionBuilder<P>,
14+
}
15+
16+
impl<P: Payload> TxBuilder<P> {
17+
pub fn new(settings: Settings, valid_until: BlockDate, payload: P) -> Self {
18+
let builder = wallet::TransactionBuilder::new(settings, payload, valid_until);
19+
Self { builder }
20+
}
21+
22+
pub fn build_tx(
23+
mut self,
24+
account_bytes: &[u8],
25+
spending_counter: SpendingCounter,
26+
) -> Result<Self, Error> {
27+
let account = EitherAccount::new_from_key(
28+
SecretKey::from_binary(account_bytes)
29+
.map_err(|e| Error::wallet_transaction().with(e))?,
30+
);
31+
// It is needed to provide a 1 extra input as we are generating it later, but should take into account at this place.
32+
let value = self.builder.estimate_fee_with(1, 0);
33+
let input = Input::from_account_public_key(account.account_id().into(), value);
34+
let witness_builder = account.witness_builder(spending_counter);
35+
self.builder.add_input(input, witness_builder);
36+
Ok(self)
37+
}
38+
39+
pub fn finalize_tx(
40+
self,
41+
auth: P::Auth,
42+
fragment_build_fn: impl FnOnce(Transaction<P>) -> Fragment,
43+
) -> Result<Fragment, Error> {
44+
Ok(fragment_build_fn(
45+
self.builder
46+
.finalize_tx(auth)
47+
.map_err(|e| Error::wallet_transaction().with(e))?,
48+
))
49+
}
50+
}

src/chain-wallet-libs/bindings/wallet-core/src/wallet.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ impl Wallet {
103103

104104
fn sign_transaction_impl<P: Payload>(
105105
&mut self,
106-
settings: &Settings,
106+
settings: Settings,
107107
valid_until: BlockDate,
108108
lane: u8,
109109
payload: P,
@@ -139,7 +139,7 @@ impl Wallet {
139139
/// This function outputs a fragment containing a signed transaction.
140140
pub fn sign_transaction(
141141
&mut self,
142-
settings: &Settings,
142+
settings: Settings,
143143
valid_until: BlockDate,
144144
lane: u8,
145145
certificate: Certificate,
@@ -183,7 +183,7 @@ impl Wallet {
183183
return Err(Error::wallet_vote_range());
184184
};
185185

186-
let mut builder = wallet::TransactionBuilder::new(&settings, payload, *valid_until);
186+
let mut builder = wallet::TransactionBuilder::new(settings, payload, *valid_until);
187187

188188
let value = builder.estimate_fee_with(1, 0);
189189

src/chain-wallet-libs/bindings/wallet-wasm-js/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ wasm-bindgen = "0.2"
3131
js-sys = "0.3.40"
3232
bech32 = "0.7.2"
3333
serde_json = "1.0"
34+
hex = "0.4.2"
3435

3536
# The `console_error_panic_hook` crate provides better debugging of panics by
3637
# logging them with `console.error`. This is great for development, but requires
@@ -45,4 +46,3 @@ clear_on_drop = {version = "0.2", features = ["no_cc"]}
4546

4647
[dev-dependencies]
4748
wasm-bindgen-test = "0.3"
48-
hex = "0.4.2"
Lines changed: 18 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,38 @@
11
var assert = require("assert");
22

3-
const private_key = Buffer.from(
4-
"c86596c2d1208885db1fe3658406aa0f7cc7b8e13c362fe46a6db277fc5064583e487588c98a6c36e2e7445c0add36f83f171cb5ccfd815509d19cd38ecb0af3",
5-
"hex"
6-
);
3+
const private_key =
4+
"c86596c2d1208885db1fe3658406aa0f7cc7b8e13c362fe46a6db277fc5064583e487588c98a6c36e2e7445c0add36f83f171cb5ccfd815509d19cd38ecb0af3";
75

86
const settings_json =
97
'{"fees":{"constant":10,"coefficient":2,"certificate":100},"discrimination":"production","block0_initial_hash":{"hash":"baf6b54817cf2a3e865f432c3922d28ac5be641e66662c66d445f141e409183e"},"block0_date":1586637936,"slot_duration":20,"time_era":{"epoch_start":0,"slot_start":0,"slots_per_epoch":180},"transaction_max_expiry_epochs":1}';
108

11-
function generate_wallet(wasm_wallet) {
12-
let wallet = new wasm_wallet.Wallet(private_key, BigInt(1000));
13-
assert(wallet.total_value() === BigInt(1000));
14-
return wallet;
15-
}
16-
179
describe("vote cast certificate tests", function () {
1810
it("public", async function () {
19-
const wasm_wallet = await import("wallet-js");
11+
const wallet = await import("wallet-js");
2012

21-
let wallet = generate_wallet(wasm_wallet);
22-
let settings = new wasm_wallet.Settings(settings_json);
23-
let vote = wasm_wallet.Vote.public(
24-
Buffer.from(
25-
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
26-
"hex"
27-
),
28-
8,
29-
0
13+
let settings = new wallet.Settings(settings_json);
14+
let proposal = new wallet.Proposal(
15+
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
16+
2,
17+
8
3018
);
31-
32-
let block_date = wasm_wallet.BlockDate.new(0, 1);
33-
let fragments = wallet.signVotes([vote], settings, block_date, 0);
19+
let vote = new wallet.Vote(proposal, 0, new wallet.BlockDate(0, 1), 1, 1);
20+
let fragments = wallet.signVotes([vote], settings, private_key);
3421
assert(fragments.length == 1);
3522
});
3623

3724
it("private", async function () {
38-
const wasm_wallet = await import("wallet-js");
25+
const wallet = await import("wallet-js");
3926

40-
let wallet = generate_wallet(wasm_wallet);
41-
let settings = new wasm_wallet.Settings(settings_json);
42-
let vote = wasm_wallet.Vote.private(
43-
Buffer.from(
44-
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
45-
"hex"
46-
),
47-
8,
27+
let settings = new wallet.Settings(settings_json);
28+
let proposal = new wallet.Proposal(
29+
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
4830
4,
49-
0,
50-
Buffer.from(
51-
"bed88887abe0a84f64691fe0bdfa3daf1a6cd697a13f07ae07588910ce39c927",
52-
"hex"
53-
)
31+
8,
32+
"bed88887abe0a84f64691fe0bdfa3daf1a6cd697a13f07ae07588910ce39c927"
5433
);
55-
56-
let block_date = wasm_wallet.BlockDate.new(0, 1);
57-
let fragments = wallet.signVotes([vote], settings, block_date, 0);
34+
let vote = new wallet.Vote(proposal, 0, new wallet.BlockDate(0, 1), 1, 1);
35+
let fragments = wallet.signVotes([vote], settings, private_key);
5836
assert(fragments.length == 1);
5937
});
6038
});

0 commit comments

Comments
 (0)