Skip to content

Commit df4d639

Browse files
committed
update icrc3
1 parent a4cdbcc commit df4d639

File tree

10 files changed

+112
-54
lines changed

10 files changed

+112
-54
lines changed

Cargo.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/icrc3/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "bity-ic-icrc3"
3-
version = "0.4.9"
3+
version = "0.5.0"
44
edition = "2021"
55
license = "MIT"
66
description = "bity icrc3 library"

src/icrc3/src/blockchain/blockchain.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,14 @@ impl Blockchain {
293293
return None;
294294
}
295295

296-
if block_id > self.chain_length() {
296+
if block_id >= self.chain_length() {
297+
// This is a non-archived block stored locally
298+
let local_index = block_id - self.chain_length();
297299
self.local_transactions
298-
.get(block_id as usize - self.chain_length() as usize - 1)
300+
.get(local_index as usize)
299301
.map(|(_, block)| block.clone())
300302
} else {
303+
// This is an archived block, we don't have it locally
301304
None
302305
}
303306
}

src/icrc3/src/icrc3.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ pub const PERMITTED_DRIFT: Duration = Duration::from_millis(100);
3030
/// * `blockchain` - The blockchain implementation
3131
/// * `ledger` - A queue of recent transactions
3232
/// * `prepared_transactions` - A FIFO queue of prepared transaction hashes
33-
/// * `last_index` - The index of the last transaction
33+
/// * `next_index` - The index of the next transaction
3434
/// * `icrc3_config` - Configuration parameters
3535
#[derive(Serialize, Deserialize)]
3636
pub struct ICRC3 {
3737
pub blockchain: Blockchain,
3838
pub ledger: VecDeque<ICRC3Value>,
3939
pub prepared_transactions: VecDeque<(String, TimestampNanos)>,
40-
pub last_index: u64,
40+
pub next_index: u64,
4141
pub last_phash: Option<ByteBuf>,
4242
pub icrc3_config: ICRC3Config,
4343
}
@@ -102,7 +102,7 @@ impl ICRC3 {
102102

103103
ledger: VecDeque::new(),
104104
prepared_transactions: VecDeque::new(),
105-
last_index: 0,
105+
next_index: 0,
106106
last_phash: None,
107107
icrc3_config,
108108
}
@@ -265,7 +265,7 @@ impl ICRC3 {
265265
/// A vector containing the root hash of the certification tree
266266
pub fn get_hash_tree(&self) -> Vec<u8> {
267267
let hash_tree_root = last_block_hash_tree(
268-
self.last_index,
268+
self.next_index,
269269
self.blockchain
270270
.last_hash
271271
.unwrap_or(HashOf::new([0; 32]))
@@ -327,7 +327,7 @@ impl From<ICRC3> for Certificate {
327327
///
328328
/// The certificate is then set as the certified data for the canister.
329329
fn from(val: ICRC3) -> Self {
330-
let last_block_index = val.last_index;
330+
let last_block_index = val.next_index - 1;
331331
let last_block_hash = val.blockchain.last_hash.unwrap_or(HashOf::new([0; 32]));
332332

333333
let leaf1 = leaf(last_block_index.to_string());

src/icrc3/src/interface.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -239,15 +239,15 @@ impl ICRC3Interface for ICRC3 {
239239
if let Some(ICRC3Value::Blob(existing_thash)) = existing_map.get("thash") {
240240
if existing_thash.as_slice() == transaction_hash {
241241
return Err(Icrc3Error::DuplicateTransaction {
242-
duplicate_of: self.last_index - i as u64,
242+
duplicate_of: self.next_index - i as u64 - 1,
243243
});
244244
}
245245
}
246246
}
247247
}
248248

249249
self.ledger.push_back(checked_transaction.clone());
250-
self.last_index += 1;
250+
self.next_index += 1;
251251
self.last_phash = Some(ByteBuf::from(transaction_hash));
252252

253253
let block = DefaultBlock::from_transaction(
@@ -263,7 +263,7 @@ impl ICRC3Interface for ICRC3 {
263263
}
264264
}
265265

266-
Ok(self.last_index)
266+
Ok(self.next_index)
267267
}
268268

269269
fn prepare_transaction<T: TransactionType>(
@@ -338,7 +338,7 @@ impl ICRC3Interface for ICRC3 {
338338
if let Some(ICRC3Value::Blob(existing_thash)) = existing_map.get("thash") {
339339
if existing_thash.as_slice() == transaction_hash {
340340
return Err(Icrc3Error::DuplicateTransaction {
341-
duplicate_of: self.last_index - i as u64,
341+
duplicate_of: self.next_index - i as u64 - 1,
342342
});
343343
}
344344
}
@@ -407,21 +407,19 @@ impl ICRC3Interface for ICRC3 {
407407
}
408408
});
409409

410-
self.last_index += 1;
411410
self.last_phash = Some(ByteBuf::from(icrc3_transaction.clone().hash().to_vec()));
412411

413412
// Add block to blockchain
414413
let block =
415414
DefaultBlock::from_transaction(self.blockchain.last_hash, icrc3_transaction, timestamp);
416415

417-
match self.blockchain.add_block(block) {
418-
Ok(_) => (),
419-
Err(e) => {
420-
return Err(Icrc3Error::Icrc3Error(e));
416+
return match self.blockchain.add_block(block) {
417+
Ok(index) => {
418+
self.next_index = index + 1;
419+
Ok(index)
421420
}
422-
}
423-
424-
Ok(self.last_index)
421+
Err(e) => Err(Icrc3Error::Icrc3Error(e)),
422+
};
425423
}
426424

427425
fn icrc3_get_archives(&self) -> Vec<ICRC3ArchiveInfo> {
@@ -443,7 +441,7 @@ impl ICRC3Interface for ICRC3 {
443441
args: Vec<GetBlocksRequest>,
444442
) -> crate::types::icrc3_get_blocks::Response {
445443
let mut response = GetBlocksResult {
446-
log_length: Nat::from(self.last_index),
444+
log_length: Nat::from(self.next_index),
447445
blocks: vec![],
448446
archived_blocks: vec![],
449447
};
@@ -457,7 +455,7 @@ impl ICRC3Interface for ICRC3 {
457455
let mut current_canister = None;
458456

459457
for i in start..start + length {
460-
if i > self.blockchain.chain_length() {
458+
if i >= self.blockchain.chain_length() {
461459
let block = self.blockchain.get_block(i);
462460

463461
if let Some(block) = block {
@@ -469,6 +467,7 @@ impl ICRC3Interface for ICRC3 {
469467
continue;
470468
}
471469
}
470+
472471
let block_canister_id = self.blockchain.get_block_canister_id(i);
473472

474473
trace(format!("block_canister_id: {:?}", block_canister_id));
-8.33 KB
Binary file not shown.

src/icrc3_canisters/canisters/icrc3_example/impl/src/updates/add_same_transactions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fn add_same_transactions(_: RandomTransactionArgs) -> RandomTransactionResponse
2727
}
2828
Err(e) => match e {
2929
bity_ic_icrc3::types::Icrc3Error::DuplicateTransaction { duplicate_of } => {
30-
if duplicate_of == 1 {
30+
if duplicate_of == 0 {
3131
trace(format!("transaction already added: {}", duplicate_of));
3232
} else {
3333
ic_cdk::trap(format!(

src/icrc3_canisters/integration_testing/src/icrc3_suite/tests/test_insert_transaction.rs

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::client::icrc3::*;
22
use crate::icrc3_suite::setup::default_test_setup;
33
use crate::utils::tick_n_blocks;
44

5+
use bity_ic_canister_time::DAY_IN_MS;
56
use candid::Nat;
67
use icrc_ledger_types::icrc3::blocks::GetBlocksRequest;
78
use std::time::Duration;
@@ -76,54 +77,111 @@ fn test_multiple_transactions() {
7677
);
7778

7879
assert_eq!(get_blocks_result.blocks.len(), 10);
79-
}
8080

81-
#[test]
82-
fn test_throttling() {
83-
let mut test_env = default_test_setup();
81+
for (i, block) in get_blocks_result.blocks.iter().enumerate() {
82+
println!("Block {}: {:?}", i, block);
83+
assert_eq!(block.id, Nat::from(i as u64));
84+
}
8485

85-
for _ in 0..15 {
86+
test_env
87+
.pic
88+
.advance_time(Duration::from_millis(DAY_IN_MS * 2));
89+
tick_n_blocks(&mut test_env.pic, 50);
90+
91+
let get_blocks_result = icrc3_get_blocks(
92+
&mut test_env.pic,
93+
test_env.controller,
94+
test_env.icrc3_id,
95+
&get_blocks_args,
96+
);
97+
98+
println!("get_blocks_result: {:?}", get_blocks_result);
99+
assert_eq!(get_blocks_result.blocks.len(), 0);
100+
assert_eq!(get_blocks_result.archived_blocks.len(), 1);
101+
102+
let archived_block = get_blocks_result.archived_blocks[0].clone();
103+
104+
let get_blocks_result_2 = icrc3_get_blocks(
105+
&mut test_env.pic,
106+
test_env.controller,
107+
archived_block.callback.canister_id,
108+
&archived_block.args,
109+
);
110+
111+
assert_eq!(get_blocks_result_2.blocks.len(), 10);
112+
assert_eq!(get_blocks_result_2.archived_blocks.len(), 0);
113+
114+
for (i, block) in get_blocks_result_2.blocks.iter().enumerate() {
115+
println!("Block {}: {:?}", i, block);
116+
assert_eq!(block.id, Nat::from(i as u64));
117+
}
118+
119+
for _ in 0..10 {
86120
add_random_transaction(
87121
&mut test_env.pic,
88122
test_env.controller,
89123
test_env.icrc3_id,
90124
&(),
91125
);
92126

93-
test_env.pic.advance_time(Duration::from_millis(100));
127+
test_env.pic.advance_time(Duration::from_secs(2));
94128
tick_n_blocks(&mut test_env.pic, 50);
95129
}
96130

97-
let get_blocks_args = vec![GetBlocksRequest {
98-
start: Nat::from(0u64),
99-
length: Nat::from(100u64),
100-
}];
101-
102131
let get_blocks_result = icrc3_get_blocks(
103132
&mut test_env.pic,
104133
test_env.controller,
105134
test_env.icrc3_id,
106135
&get_blocks_args,
107136
);
108137

109-
assert_eq!(get_blocks_result.blocks.len(), 13);
110-
assert_eq!(get_blocks_result.archived_blocks.len(), 0);
111-
}
138+
println!("get_blocks_result: {:?}", get_blocks_result);
139+
assert_eq!(get_blocks_result.blocks.len(), 10);
140+
assert_eq!(get_blocks_result.archived_blocks.len(), 1);
112141

113-
#[test]
114-
fn test_concurrent_transactions() {
115-
let mut test_env = default_test_setup();
142+
let archived_block = get_blocks_result.archived_blocks[0].clone();
116143

117-
add_same_transactions(
144+
let get_blocks_result_2 = icrc3_get_blocks(
118145
&mut test_env.pic,
119146
test_env.controller,
120-
test_env.icrc3_id,
121-
&(),
147+
archived_block.callback.canister_id,
148+
&archived_block.args,
122149
);
123150

151+
println!("get_blocks_result_2: {:?}", get_blocks_result_2);
152+
assert_eq!(get_blocks_result_2.blocks.len(), 10);
153+
assert_eq!(get_blocks_result_2.archived_blocks.len(), 0);
154+
155+
for (i, block) in get_blocks_result.blocks.iter().enumerate() {
156+
println!("Block {}: {:?}", i, block);
157+
assert_eq!(block.id, Nat::from(i as u64 + 10));
158+
}
159+
160+
for (i, block) in get_blocks_result_2.blocks.iter().enumerate() {
161+
println!("Block {}: {:?}", i, block);
162+
assert_eq!(block.id, Nat::from(i as u64));
163+
}
164+
}
165+
166+
#[test]
167+
fn test_throttling() {
168+
let mut test_env = default_test_setup();
169+
170+
for _ in 0..15 {
171+
add_random_transaction(
172+
&mut test_env.pic,
173+
test_env.controller,
174+
test_env.icrc3_id,
175+
&(),
176+
);
177+
178+
test_env.pic.advance_time(Duration::from_millis(100));
179+
tick_n_blocks(&mut test_env.pic, 50);
180+
}
181+
124182
let get_blocks_args = vec![GetBlocksRequest {
125183
start: Nat::from(0u64),
126-
length: Nat::from(10u64),
184+
length: Nat::from(100u64),
127185
}];
128186

129187
let get_blocks_result = icrc3_get_blocks(
@@ -133,9 +191,7 @@ fn test_concurrent_transactions() {
133191
&get_blocks_args,
134192
);
135193

136-
println!("get_blocks_result: {:?}", get_blocks_result);
137-
138-
assert_eq!(get_blocks_result.blocks.len(), 1);
194+
assert_eq!(get_blocks_result.blocks.len(), 13);
139195
assert_eq!(get_blocks_result.archived_blocks.len(), 0);
140196
}
141197

-8.33 KB
Binary file not shown.
-25.2 KB
Binary file not shown.

0 commit comments

Comments
 (0)