From b01c37d886a47d8c43680a9ef3d7d49d1a447e5e Mon Sep 17 00:00:00 2001
From: librelois <elois@ifee.fr>
Date: Sun, 23 Jun 2019 14:30:13 +0200
Subject: [PATCH] [ref] documents: versioning block document
---
.../blockchain-dal/src/entities/block.rs | 2 +-
.../blockchain-dal/src/readers/block.rs | 11 +-
.../src/readers/currency_params.rs | 34 +-
.../blockchain/blockchain-dal/src/tools.rs | 11 +-
.../blockchain-dal/src/writers/block.rs | 5 +-
.../blockchain-dal/src/writers/requests.rs | 6 +-
lib/modules/blockchain/blockchain/src/dbex.rs | 5 +-
.../blockchain/src/dubp/apply/mod.rs | 20 +-
.../blockchain/src/dubp/check/hashs.rs | 17 +-
.../blockchain/src/dubp/check/mod.rs | 8 +-
.../blockchain/blockchain/src/dubp/mod.rs | 15 +-
.../blockchain/src/fork/fork_algo.rs | 70 +-
.../blockchain/src/fork/revert_block.rs | 50 +-
.../blockchain/src/fork/rollback.rs | 4 +-
.../blockchain/src/fork/stackable_blocks.rs | 5 +-
.../src/sync/download/json_reader_worker.rs | 2 +-
.../blockchain/blockchain/src/sync/mod.rs | 7 +-
lib/modules/ws2p-v1-legacy/src/lib.rs | 10 +-
.../ws2p-v1-legacy/src/serializers/block.rs | 10 +-
.../documents-tests-tools/src/mocks/mod.rs | 15 +-
lib/tools/currency-params/src/lib.rs | 6 +
lib/tools/documents/src/documents/block.rs | 1024 +++--------------
.../documents/src/documents/block/v10.rs | 954 +++++++++++++++
.../documents/src/documents/certification.rs | 1 -
lib/tools/documents/src/documents/identity.rs | 1 -
.../documents/src/documents/membership.rs | 1 -
lib/tools/documents/src/documents/mod.rs | 5 +-
.../documents/src/documents/revocation.rs | 1 -
.../documents/src/documents/transaction.rs | 1 -
lib/tools/documents/src/lib.rs | 44 +-
lib/tools/documents/src/parsers/blocks.rs | 20 +-
.../documents/src/text_document_traits.rs | 2 +-
32 files changed, 1357 insertions(+), 1010 deletions(-)
create mode 100644 lib/tools/documents/src/documents/block/v10.rs
diff --git a/lib/modules/blockchain/blockchain-dal/src/entities/block.rs b/lib/modules/blockchain/blockchain-dal/src/entities/block.rs
index cc4ca8b0..b22ade1d 100644
--- a/lib/modules/blockchain/blockchain-dal/src/entities/block.rs
+++ b/lib/modules/blockchain/blockchain-dal/src/entities/block.rs
@@ -14,7 +14,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::*;
-use dubp_documents::documents::block::BlockDocument;
+use dubp_documents::documents::block::{BlockDocument, BlockDocumentTrait};
use dubp_documents::Document;
use dubp_documents::{BlockNumber, Blockstamp};
use durs_wot::NodeId;
diff --git a/lib/modules/blockchain/blockchain-dal/src/readers/block.rs b/lib/modules/blockchain/blockchain-dal/src/readers/block.rs
index a9414bc4..8df1aa1b 100644
--- a/lib/modules/blockchain/blockchain-dal/src/readers/block.rs
+++ b/lib/modules/blockchain/blockchain-dal/src/readers/block.rs
@@ -14,7 +14,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::*;
-use dubp_documents::documents::block::BlockDocument;
+use dubp_documents::documents::block::{BlockDocument, BlockDocumentTrait};
use dubp_documents::Document;
use dubp_documents::{BlockHash, BlockNumber, Blockstamp};
use dup_crypto::keys::*;
@@ -42,7 +42,7 @@ pub fn get_block_hash(
) -> Result<Option<BlockHash>, DALError> {
Ok(db.read(|db| {
if let Some(dal_block) = db.get(&block_number) {
- dal_block.block.hash
+ dal_block.block.hash()
} else {
None
}
@@ -86,7 +86,7 @@ pub fn already_have_block(
} else {
return Ok(blockchain_db.read(|db| {
if let Some(dal_block) = db.get(&blockstamp.id) {
- if dal_block.block.hash.unwrap_or_default() == blockstamp.hash {
+ if dal_block.block.hash().unwrap_or_default() == blockstamp.hash {
return true;
}
}
@@ -151,10 +151,11 @@ pub fn get_current_frame(
current_block: &DALBlock,
db: &BinDB<LocalBlockchainV10Datas>,
) -> Result<HashMap<PubKey, usize>, DALError> {
- let frame_begin = current_block.block.number.0 - current_block.block.issuers_frame as u32;
+ let frame_begin =
+ current_block.block.number().0 - current_block.block.current_frame_size() as u32;
Ok(db.read(|db| {
let mut current_frame: HashMap<PubKey, usize> = HashMap::new();
- for block_number in frame_begin..current_block.block.number.0 {
+ for block_number in frame_begin..current_block.block.number().0 {
let issuer = db
.get(&BlockNumber(block_number))
.unwrap_or_else(|| fatal_error!("Fail to get block #{} !", block_number))
diff --git a/lib/modules/blockchain/blockchain-dal/src/readers/currency_params.rs b/lib/modules/blockchain/blockchain-dal/src/readers/currency_params.rs
index 44dec3e6..2be4b61d 100644
--- a/lib/modules/blockchain/blockchain-dal/src/readers/currency_params.rs
+++ b/lib/modules/blockchain/blockchain-dal/src/readers/currency_params.rs
@@ -14,7 +14,8 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::*;
-use dubp_documents::documents::block::BlockDocument;
+use dubp_documents::documents::block::{BlockDocument, BlockDocumentTrait};
+use dubp_documents::Document;
use dup_currency_params::db::write_currency_params;
use dup_currency_params::genesis_block_params::GenesisBlockParams;
use dup_currency_params::CurrencyParameters;
@@ -25,17 +26,26 @@ pub fn get_and_write_currency_params(
db_path: &PathBuf,
genesis_block: &BlockDocument,
) -> CurrencyParameters {
- if genesis_block.number.0 != 0 {
+ if genesis_block.number().0 != 0 {
fatal_error!("The genesis block must have number equal to zero !");
- } else if genesis_block.parameters.is_none() {
- fatal_error!("The genesis block must have parameters !");
- } else if let Err(e) = write_currency_params(
- db_path.clone(),
- genesis_block.currency.clone(),
- GenesisBlockParams::V10(unwrap!(genesis_block.parameters)),
- ) {
- fatal_error!("Fail to write currency parameters: {}", e);
- } else {
- CurrencyParameters::from((&genesis_block.currency, unwrap!(genesis_block.parameters)))
+ }
+
+ match genesis_block {
+ BlockDocument::V10(genesis_block_v10) => {
+ if genesis_block_v10.parameters.is_none() {
+ fatal_error!("The genesis block must have parameters !");
+ } else if let Err(e) = write_currency_params(
+ db_path.clone(),
+ genesis_block_v10.currency().into(),
+ GenesisBlockParams::V10(unwrap!(genesis_block_v10.parameters)),
+ ) {
+ fatal_error!("Fail to write currency parameters: {}", e);
+ } else {
+ CurrencyParameters::from((
+ &genesis_block_v10.currency().into(),
+ unwrap!(genesis_block_v10.parameters),
+ ))
+ }
+ }
}
}
diff --git a/lib/modules/blockchain/blockchain-dal/src/tools.rs b/lib/modules/blockchain/blockchain-dal/src/tools.rs
index 7554cdd8..dc12918b 100644
--- a/lib/modules/blockchain/blockchain-dal/src/tools.rs
+++ b/lib/modules/blockchain/blockchain-dal/src/tools.rs
@@ -14,6 +14,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::entities::block::DALBlock;
+use dubp_documents::documents::block::BlockDocumentTrait;
use dup_crypto::keys::PubKey;
use durs_common_tools::fatal_error;
use durs_wot::operations::centrality::{CentralitiesCalculator, UlrikBrandesCentralityCalculator};
@@ -151,12 +152,12 @@ pub fn compute_median_issuers_frame<S: std::hash::BuildHasher>(
current_frame_vec.sort_unstable();
// Calculate median
- let mut median_index = match current_block.block.issuers_count % 2 {
- 1 => (current_block.block.issuers_count / 2) + 1,
- _ => current_block.block.issuers_count / 2,
+ let mut median_index = match current_block.block.issuers_count() % 2 {
+ 1 => (current_block.block.issuers_count() / 2) + 1,
+ _ => current_block.block.issuers_count() / 2,
};
- if median_index >= current_block.block.issuers_count {
- median_index = current_block.block.issuers_count - 1;
+ if median_index >= current_block.block.issuers_count() {
+ median_index = current_block.block.issuers_count() - 1;
}
current_frame_vec[median_index]
diff --git a/lib/modules/blockchain/blockchain-dal/src/writers/block.rs b/lib/modules/blockchain/blockchain-dal/src/writers/block.rs
index ecbf6dde..47a27058 100644
--- a/lib/modules/blockchain/blockchain-dal/src/writers/block.rs
+++ b/lib/modules/blockchain/blockchain-dal/src/writers/block.rs
@@ -16,6 +16,7 @@
use crate::entities::block::DALBlock;
use crate::*;
use crate::{BinDB, DALError, LocalBlockchainV10Datas};
+use dubp_documents::documents::block::BlockDocumentTrait;
use dubp_documents::Document;
use unwrap::unwrap;
@@ -27,7 +28,7 @@ pub fn insert_new_head_block(
) -> Result<(), DALError> {
// Insert head block in blockchain
blockchain_db.write(|db| {
- db.insert(dal_block.block.number, dal_block.clone());
+ db.insert(dal_block.block.number(), dal_block.clone());
})?;
// Insert head block in fork tree
@@ -56,7 +57,7 @@ pub fn insert_new_fork_block(forks_dbs: &ForksDBs, dal_block: DALBlock) -> Resul
if crate::writers::fork_tree::insert_new_fork_block(
&forks_dbs.fork_tree_db,
dal_block.block.blockstamp(),
- unwrap!(dal_block.block.previous_hash),
+ unwrap!(dal_block.block.previous_hash()),
)? {
// Insert in ForksBlocks
forks_dbs.fork_blocks_db.write(|db| {
diff --git a/lib/modules/blockchain/blockchain-dal/src/writers/requests.rs b/lib/modules/blockchain/blockchain-dal/src/writers/requests.rs
index 22fb9a3f..be8610a5 100644
--- a/lib/modules/blockchain/blockchain-dal/src/writers/requests.rs
+++ b/lib/modules/blockchain/blockchain-dal/src/writers/requests.rs
@@ -17,7 +17,7 @@ use crate::entities::block::DALBlock;
use crate::entities::sources::SourceAmount;
use crate::writers::transaction::DALTxV10;
use crate::*;
-use dubp_documents::documents::block::BlockDocument;
+use dubp_documents::documents::block::{BlockDocument, BlockDocumentTrait};
use dubp_documents::documents::certification::CompactCertificationDocument;
use dubp_documents::documents::identity::IdentityDocument;
use dubp_documents::Blockstamp;
@@ -74,7 +74,7 @@ impl BlocksDBsWriteQuery {
} else {
// Insert block in blockchain
blockchain_db.write(|db| {
- db.insert(dal_block.block.number, dal_block);
+ db.insert(dal_block.block.number(), dal_block);
})?;
}
}
@@ -82,7 +82,7 @@ impl BlocksDBsWriteQuery {
trace!("BlocksDBsWriteQuery::WriteBlock...");
// Remove block in blockchain
blockchain_db.write(|db| {
- db.remove(&dal_block.block.number);
+ db.remove(&dal_block.block.number());
})?;
trace!("BlocksDBsWriteQuery::WriteBlock...finish");
}
diff --git a/lib/modules/blockchain/blockchain/src/dbex.rs b/lib/modules/blockchain/blockchain/src/dbex.rs
index e74145a6..ab4767a4 100644
--- a/lib/modules/blockchain/blockchain/src/dbex.rs
+++ b/lib/modules/blockchain/blockchain/src/dbex.rs
@@ -14,6 +14,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::*;
+use dubp_documents::documents::block::BlockDocumentTrait;
use dubp_documents::documents::transaction::*;
use dup_crypto::keys::*;
use durs_wot::data::rusty::RustyWebOfTrust;
@@ -242,9 +243,9 @@ pub fn dbex_wot(profile_path: PathBuf, csv: bool, query: &DBExWotQuery) {
let (current_bc_time, blocks_times): (u64, HashMap<BlockNumber, u64>) = blockchain_db
.read(|db| {
(
- db[&BlockNumber(db.len() as u32 - 1)].block.median_time,
+ db[&BlockNumber(db.len() as u32 - 1)].block.common_time(),
db.iter()
- .map(|(block_id, dal_block)| (*block_id, dal_block.block.median_time))
+ .map(|(block_id, dal_block)| (*block_id, dal_block.block.common_time()))
.collect(),
)
})
diff --git a/lib/modules/blockchain/blockchain/src/dubp/apply/mod.rs b/lib/modules/blockchain/blockchain/src/dubp/apply/mod.rs
index 058865a0..3cef4d90 100644
--- a/lib/modules/blockchain/blockchain/src/dubp/apply/mod.rs
+++ b/lib/modules/blockchain/blockchain/src/dubp/apply/mod.rs
@@ -15,7 +15,7 @@
//! Sub-module that applies the content of a block to the indexes of the local blockchain.
-use dubp_documents::documents::block::BlockDocument;
+use dubp_documents::documents::block::{BlockDocument, BlockDocumentTrait, BlockDocumentV10};
use dubp_documents::documents::transaction::{TxAmount, TxBase};
use dubp_documents::{BlockNumber, Document};
use dup_crypto::keys::*;
@@ -44,8 +44,22 @@ pub enum ApplyValidBlockError {
RevokeUnknowNodeId,
}
+#[inline]
pub fn apply_valid_block<W: WebOfTrust>(
- mut block: BlockDocument,
+ block: BlockDocument,
+ wot_index: &mut HashMap<PubKey, NodeId>,
+ wot_db: &BinDB<W>,
+ expire_certs: &HashMap<(NodeId, NodeId), BlockNumber>,
+) -> Result<ValidBlockApplyReqs, ApplyValidBlockError> {
+ match block {
+ BlockDocument::V10(block_v10) => {
+ apply_valid_block_v10(block_v10, wot_index, wot_db, expire_certs)
+ }
+ }
+}
+
+pub fn apply_valid_block_v10<W: WebOfTrust>(
+ mut block: BlockDocumentV10,
wot_index: &mut HashMap<PubKey, NodeId>,
wot_db: &BinDB<W>,
expire_certs: &HashMap<(NodeId, NodeId), BlockNumber>,
@@ -270,7 +284,7 @@ pub fn apply_valid_block<W: WebOfTrust>(
// Create DALBlock
block.reduce();
let dal_block = DALBlock {
- block,
+ block: BlockDocument::V10(block),
expire_certs: Some(expire_certs.clone()),
};
// Return DBs requests
diff --git a/lib/modules/blockchain/blockchain/src/dubp/check/hashs.rs b/lib/modules/blockchain/blockchain/src/dubp/check/hashs.rs
index bee20349..81a9d785 100644
--- a/lib/modules/blockchain/blockchain/src/dubp/check/hashs.rs
+++ b/lib/modules/blockchain/blockchain/src/dubp/check/hashs.rs
@@ -16,28 +16,21 @@
//! Verify block inner hash and block hash
use crate::VerifyBlockHashsError;
-use dubp_documents::documents::block::BlockDocument;
-use durs_common_tools::fatal_error;
+use dubp_documents::documents::block::{BlockDocument, BlockDocumentTrait};
/// Verify block hashs
pub fn verify_block_hashs(block_doc: &BlockDocument) -> Result<(), VerifyBlockHashsError> {
- trace!("complete_block #{}...", block_doc.number);
-
- if block_doc.inner_hash.is_none() {
- fatal_error!(
- "BlockchainModule : verify_block_hashs() : fatal error : block.inner_hash = None",
- );
- }
+ trace!("complete_block #{}...", block_doc.number());
if block_doc.verify_inner_hash() {
if block_doc.verify_hash() {
- trace!("Succes to verify_block_hashs #{}", block_doc.number.0);
+ trace!("Succes to verify_block_hashs #{}", block_doc.number().0);
Ok(())
} else {
warn!("BlockchainModule : Refuse Bloc : invalid hash !");
Err(VerifyBlockHashsError::InvalidHash(
- block_doc.number,
- block_doc.hash,
+ block_doc.number(),
+ block_doc.hash(),
))
}
} else {
diff --git a/lib/modules/blockchain/blockchain/src/dubp/check/mod.rs b/lib/modules/blockchain/blockchain/src/dubp/check/mod.rs
index 0c9959ba..b14762ea 100644
--- a/lib/modules/blockchain/blockchain/src/dubp/check/mod.rs
+++ b/lib/modules/blockchain/blockchain/src/dubp/check/mod.rs
@@ -18,7 +18,7 @@
pub mod hashs;
use crate::dubp::BlockError;
-use dubp_documents::documents::block::BlockDocument;
+use dubp_documents::documents::block::{BlockDocument, BlockDocumentTrait};
use dubp_documents::*;
use dup_crypto::keys::PubKey;
use durs_blockchain_dal::*;
@@ -39,11 +39,11 @@ pub fn verify_block_validity<W: WebOfTrust>(
_wot_db: &BinDB<W>,
) -> Result<(), BlockError> {
// Rules that do not concern genesis block
- if block.number.0 > 0 {
+ if block.number().0 > 0 {
// Get previous block
let previous_block_opt = readers::block::get_block_in_local_blockchain(
blockchain_db,
- BlockNumber(block.number.0 - 1),
+ BlockNumber(block.number().0 - 1),
)?;
// Previous block must exist
@@ -53,7 +53,7 @@ pub fn verify_block_validity<W: WebOfTrust>(
let previous_block = previous_block_opt.expect("safe unwrap");
// Block version must not decrease
- if previous_block.version > block.version {
+ if previous_block.version() > block.version() {
return Err(BlockError::InvalidBlock(InvalidBlockError::VersionDecrease));
}
}
diff --git a/lib/modules/blockchain/blockchain/src/dubp/mod.rs b/lib/modules/blockchain/blockchain/src/dubp/mod.rs
index 2b2b7fee..87a588b5 100644
--- a/lib/modules/blockchain/blockchain/src/dubp/mod.rs
+++ b/lib/modules/blockchain/blockchain/src/dubp/mod.rs
@@ -21,6 +21,7 @@ pub mod check;
use crate::*;
use apply::*;
use check::*;
+use dubp_documents::documents::block::BlockDocumentTrait;
use dubp_documents::Blockstamp;
use dubp_documents::Document;
use durs_blockchain_dal::entities::block::DALBlock;
@@ -71,16 +72,16 @@ pub fn check_and_apply_block(
&bc.blocks_databases.blockchain_db,
&bc.forks_dbs,
block_doc.blockstamp(),
- block_doc.previous_hash,
+ block_doc.previous_hash(),
)?;
// Verify block hashs
dubp::check::hashs::verify_block_hashs(&block_doc)?;
// Check block chainability
- if (block_doc.number.0 == 0 && bc.current_blockstamp == Blockstamp::default())
- || (block_doc.number.0 == bc.current_blockstamp.id.0 + 1
- && unwrap!(block_doc.previous_hash).to_string()
+ if (block_doc.number().0 == 0 && bc.current_blockstamp == Blockstamp::default())
+ || (block_doc.number().0 == bc.current_blockstamp.id.0 + 1
+ && unwrap!(block_doc.previous_hash()).to_string()
== bc.current_blockstamp.hash.0.to_string())
{
debug!(
@@ -104,7 +105,7 @@ pub fn check_and_apply_block(
)?;
// If we're in block genesis, get the currency parameters
- if block_doc.number == BlockNumber(0) {
+ if block_doc.number() == BlockNumber(0) {
// Open currency_params_db
let datas_path = durs_conf::get_datas_path(bc.profile_path.clone());
// Get and write currency params
@@ -124,8 +125,8 @@ pub fn check_and_apply_block(
)?))
} else if already_have_block {
Err(BlockError::AlreadyHaveBlock)
- } else if block_doc.number.0 >= bc.current_blockstamp.id.0
- || (bc.current_blockstamp.id.0 - block_doc.number.0)
+ } else if block_doc.number().0 >= bc.current_blockstamp.id.0
+ || (bc.current_blockstamp.id.0 - block_doc.number().0)
< unwrap!(bc.currency_params).fork_window_size as u32
{
debug!(
diff --git a/lib/modules/blockchain/blockchain/src/fork/fork_algo.rs b/lib/modules/blockchain/blockchain/src/fork/fork_algo.rs
index d0d9b178..2784da53 100644
--- a/lib/modules/blockchain/blockchain/src/fork/fork_algo.rs
+++ b/lib/modules/blockchain/blockchain/src/fork/fork_algo.rs
@@ -13,6 +13,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
+use dubp_documents::documents::block::BlockDocumentTrait;
use dubp_documents::Blockstamp;
use durs_blockchain_dal::entities::fork_tree::ForkTree;
use durs_blockchain_dal::{DALError, ForksDBs};
@@ -33,7 +34,7 @@ pub fn fork_resolution_algo(
db.get(¤t_blockstamp)
.expect("safe unwrap")
.block
- .median_time
+ .common_time()
})?;
let mut sheets = forks_dbs.fork_tree_db.read(ForkTree::get_sheets)?;
@@ -55,7 +56,7 @@ pub fn fork_resolution_algo(
db.get(&branch_head_blockstamp)
.expect("safe unwrap")
.block
- .median_time
+ .common_time()
})?;
if branch_head_blockstamp.id.0 >= current_blockstamp.id.0 + *ADVANCE_BLOCKS
&& branch_head_median_time >= current_bc_time + *ADVANCE_TIME
@@ -102,7 +103,10 @@ mod tests {
// Generate `FORK_WINDOW_SIZE + 2` mock blocks
let main_branch: Vec<BlockDocument> =
- dubp_documents_tests_tools::mocks::gen_empty_timed_blocks(fork_window_size + 2, 0u64);
+ dubp_documents_tests_tools::mocks::gen_empty_timed_blocks_v10(
+ fork_window_size + 2,
+ 0u64,
+ );
// Insert mock blocks in forks_dbs
for block in &main_branch {
@@ -136,17 +140,19 @@ mod tests {
let fork_point = &main_branch[main_branch.len() - 2];
let fork_blocks: Vec<BlockDocument> = (0..3)
.map(|i| {
- dubp_documents_tests_tools::mocks::gen_empty_timed_block(
- Blockstamp {
- id: BlockNumber(fork_point.number.0 + i + 1),
- hash: BlockHash(dup_crypto_tests_tools::mocks::hash('A')),
- },
- ADVANCE_TIME - 1,
- if i == 0 {
- fork_point.hash.expect("safe unwrap").0
- } else {
- dup_crypto_tests_tools::mocks::hash('A')
- },
+ BlockDocument::V10(
+ dubp_documents_tests_tools::mocks::gen_empty_timed_block_v10(
+ Blockstamp {
+ id: BlockNumber(fork_point.number().0 + i + 1),
+ hash: BlockHash(dup_crypto_tests_tools::mocks::hash('A')),
+ },
+ ADVANCE_TIME - 1,
+ if i == 0 {
+ fork_point.hash().expect("safe unwrap").0
+ } else {
+ dup_crypto_tests_tools::mocks::hash('A')
+ },
+ ),
)
})
.collect();
@@ -173,7 +179,7 @@ mod tests {
// Add the determining fork block
let determining_blockstamp = Blockstamp {
- id: BlockNumber(fork_point.number.0 + 4),
+ id: BlockNumber(fork_point.number().0 + 4),
hash: BlockHash(dup_crypto_tests_tools::mocks::hash('A')),
};
assert_eq!(
@@ -181,10 +187,12 @@ mod tests {
durs_blockchain_dal::writers::block::insert_new_fork_block(
&forks_dbs,
DALBlock {
- block: dubp_documents_tests_tools::mocks::gen_empty_timed_block(
- determining_blockstamp,
- *ADVANCE_TIME,
- dup_crypto_tests_tools::mocks::hash('A'),
+ block: BlockDocument::V10(
+ dubp_documents_tests_tools::mocks::gen_empty_timed_block_v10(
+ determining_blockstamp,
+ *ADVANCE_TIME,
+ dup_crypto_tests_tools::mocks::hash('A'),
+ )
),
expire_certs: None,
},
@@ -211,17 +219,19 @@ mod tests {
// The old main branch catches up and overlaps with the fork
let new_main_blocks: Vec<BlockDocument> = (0..7)
.map(|i| {
- dubp_documents_tests_tools::mocks::gen_empty_timed_block(
- Blockstamp {
- id: BlockNumber(fork_point.number.0 + i + 1),
- hash: BlockHash(dup_crypto_tests_tools::mocks::hash('B')),
- },
- ADVANCE_TIME * 2,
- if i == 0 {
- fork_point.hash.expect("safe unwrap").0
- } else {
- dup_crypto_tests_tools::mocks::hash('B')
- },
+ BlockDocument::V10(
+ dubp_documents_tests_tools::mocks::gen_empty_timed_block_v10(
+ Blockstamp {
+ id: BlockNumber(fork_point.number().0 + i + 1),
+ hash: BlockHash(dup_crypto_tests_tools::mocks::hash('B')),
+ },
+ ADVANCE_TIME * 2,
+ if i == 0 {
+ fork_point.hash().expect("safe unwrap").0
+ } else {
+ dup_crypto_tests_tools::mocks::hash('B')
+ },
+ ),
)
})
.collect();
diff --git a/lib/modules/blockchain/blockchain/src/fork/revert_block.rs b/lib/modules/blockchain/blockchain/src/fork/revert_block.rs
index 9966c0ba..09e09935 100644
--- a/lib/modules/blockchain/blockchain/src/fork/revert_block.rs
+++ b/lib/modules/blockchain/blockchain/src/fork/revert_block.rs
@@ -15,9 +15,10 @@
//! Sub-module that applies a block backwards.
-use dubp_documents::documents::block::TxDocOrTxHash;
+use dubp_documents::documents::block::v10::TxDocOrTxHash;
+use dubp_documents::documents::block::{BlockDocument, BlockDocumentTrait, BlockDocumentV10};
use dubp_documents::documents::transaction::{TxAmount, TxBase};
-use dubp_documents::Document;
+use dubp_documents::{BlockNumber, Document};
use dup_crypto::keys::*;
use durs_blockchain_dal::entities::block::DALBlock;
use durs_blockchain_dal::entities::sources::SourceAmount;
@@ -28,6 +29,7 @@ use durs_common_tools::fatal_error;
use durs_wot::data::{NewLinkResult, RemLinkResult};
use durs_wot::{NodeId, WebOfTrust};
use std::collections::HashMap;
+use unwrap::unwrap;
#[derive(Debug)]
/// Stores all queries to apply in database to "apply" the block
@@ -52,18 +54,29 @@ impl From<DALError> for RevertValidBlockError {
}
pub fn revert_block<W: WebOfTrust>(
- dal_block: &DALBlock,
+ dal_block: DALBlock,
wot_index: &mut HashMap<PubKey, NodeId>,
wot_db: &BinDB<W>,
txs_db: &BinDB<TxV10Datas>,
) -> Result<ValidBlockRevertReqs, RevertValidBlockError> {
- // Revert DALBlock
- let mut block = dal_block.block.clone();
- let expire_certs = dal_block
- .expire_certs
- .clone()
- .expect("Try to get expire_certs of an uncompleted block !");
+ match dal_block.block {
+ BlockDocument::V10(block_v10) => revert_block_v10(
+ block_v10,
+ unwrap!(dal_block.expire_certs),
+ wot_index,
+ wot_db,
+ txs_db,
+ ),
+ }
+}
+pub fn revert_block_v10<W: WebOfTrust>(
+ mut block: BlockDocumentV10,
+ expire_certs: HashMap<(NodeId, NodeId), BlockNumber>,
+ wot_index: &mut HashMap<PubKey, NodeId>,
+ wot_db: &BinDB<W>,
+ txs_db: &BinDB<TxV10Datas>,
+) -> Result<ValidBlockRevertReqs, RevertValidBlockError> {
// Get transactions
let dal_txs: Vec<DALTxV10> = block
.transactions
@@ -81,7 +94,7 @@ pub fn revert_block<W: WebOfTrust>(
.collect();
// Revert reduce block
- block.compute_inner_hash();
+ block.generate_inner_hash();
debug!(
"BlockchainModule : revert_valid_block({})",
block.blockstamp()
@@ -116,10 +129,10 @@ pub fn revert_block<W: WebOfTrust>(
let mut wot_dbs_requests = Vec::new();
// Revert expire_certs
if !expire_certs.is_empty() {
- for ((source, target), created_block_id) in expire_certs {
+ for ((source, target), created_block_id) in &expire_certs {
wot_db
.write(|db| {
- let result = db.add_link(source, target);
+ let result = db.add_link(*source, *target);
match result {
NewLinkResult::Ok(_) => {}
_ => fatal_error!(
@@ -132,9 +145,9 @@ pub fn revert_block<W: WebOfTrust>(
})
.expect("Fail to write in WotDB");
wot_dbs_requests.push(WotsDBsWriteQuery::RevertExpireCert(
- source,
- target,
- created_block_id,
+ *source,
+ *target,
+ *created_block_id,
));
}
}
@@ -247,14 +260,17 @@ pub fn revert_block<W: WebOfTrust>(
wot_dbs_requests.push(WotsDBsWriteQuery::RevertRenewalIdentity(
joiner.issuers()[0],
wot_id,
- block.median_time,
+ block.common_time(),
joiner.blockstamp().id,
));
}
}
// Return DBs requests
Ok(ValidBlockRevertReqs(
- BlocksDBsWriteQuery::RevertBlock(dal_block.clone()),
+ BlocksDBsWriteQuery::RevertBlock(DALBlock {
+ block: BlockDocument::V10(block),
+ expire_certs: Some(expire_certs),
+ }),
wot_dbs_requests,
currency_dbs_requests,
))
diff --git a/lib/modules/blockchain/blockchain/src/fork/rollback.rs b/lib/modules/blockchain/blockchain/src/fork/rollback.rs
index fa060ea3..df2f602f 100644
--- a/lib/modules/blockchain/blockchain/src/fork/rollback.rs
+++ b/lib/modules/blockchain/blockchain/src/fork/rollback.rs
@@ -37,9 +37,10 @@ pub fn apply_rollback(bc: &mut BlockchainModule, new_bc_branch: Vec<Blockstamp>)
fatal_error!("revert block {} fail !", bc.current_blockstamp);
})
{
+ let blockstamp = dal_block.block.blockstamp();
let ValidBlockRevertReqs(bc_db_query, wot_dbs_queries, tx_dbs_queries) =
super::revert_block::revert_block(
- &dal_block,
+ dal_block,
&mut bc.wot_index,
&bc.wot_databases.wot_db,
&bc.currency_databases.tx_db,
@@ -47,7 +48,6 @@ pub fn apply_rollback(bc: &mut BlockchainModule, new_bc_branch: Vec<Blockstamp>)
.unwrap_or_else(|_| {
fatal_error!("revert block {} fail !", bc.current_blockstamp);
});
- let blockstamp = dal_block.block.blockstamp();
// Apply db requests
bc_db_query
.apply(
diff --git a/lib/modules/blockchain/blockchain/src/fork/stackable_blocks.rs b/lib/modules/blockchain/blockchain/src/fork/stackable_blocks.rs
index f6aeaf8a..905d059d 100644
--- a/lib/modules/blockchain/blockchain/src/fork/stackable_blocks.rs
+++ b/lib/modules/blockchain/blockchain/src/fork/stackable_blocks.rs
@@ -16,6 +16,7 @@
//! Sub-module that finds and applies the orphaned blocks that have become stackable on the local blockchain.
use crate::*;
+use dubp_documents::documents::block::BlockDocumentTrait;
use unwrap::unwrap;
pub fn apply_stackable_blocks(bc: &mut BlockchainModule) {
@@ -29,9 +30,9 @@ pub fn apply_stackable_blocks(bc: &mut BlockchainModule) {
break 'blockchain;
} else {
for stackable_block in stackable_blocks {
- debug!("stackable_block({})", stackable_block.block.number);
+ debug!("stackable_block({})", stackable_block.block.number());
- let stackable_block_number = stackable_block.block.number;
+ let stackable_block_number = stackable_block.block.number();
let stackable_block_blockstamp = stackable_block.block.blockstamp();
if let Ok(CheckAndApplyBlockReturn::ValidMainBlock(ValidBlockApplyReqs(
diff --git a/lib/modules/blockchain/blockchain/src/sync/download/json_reader_worker.rs b/lib/modules/blockchain/blockchain/src/sync/download/json_reader_worker.rs
index 6e2dac28..1c038957 100644
--- a/lib/modules/blockchain/blockchain/src/sync/download/json_reader_worker.rs
+++ b/lib/modules/blockchain/blockchain/src/sync/download/json_reader_worker.rs
@@ -87,7 +87,7 @@ pub fn json_reader_worker(
// Send TargetBlockcstamp
sender_sync_thread
.send(MessForSyncThread::Target(
- last_block.currency.clone(),
+ last_block.currency().into(),
last_block.blockstamp(),
))
.expect("Fatal error : sync_thread unrechable !");
diff --git a/lib/modules/blockchain/blockchain/src/sync/mod.rs b/lib/modules/blockchain/blockchain/src/sync/mod.rs
index 5986d6f1..7c9b07bd 100644
--- a/lib/modules/blockchain/blockchain/src/sync/mod.rs
+++ b/lib/modules/blockchain/blockchain/src/sync/mod.rs
@@ -18,6 +18,7 @@ mod download;
use crate::dubp::apply::apply_valid_block;
use crate::*;
+use dubp_documents::documents::block::BlockDocumentTrait;
use dubp_documents::{BlockHash, BlockNumber};
use dup_crypto::keys::*;
use dup_currency_params::{CurrencyName, CurrencyParameters};
@@ -251,7 +252,7 @@ pub fn local_sync<DC: DursConfTrait>(profile_path: PathBuf, conf: &DC, sync_opts
// Get and write currency params
if !get_currency_params {
let datas_path = durs_conf::get_datas_path(profile_path.clone());
- if block_doc.number == BlockNumber(0) {
+ if block_doc.number() == BlockNumber(0) {
currency_params = Some(
durs_blockchain_dal::readers::currency_params::get_and_write_currency_params(
&datas_path,
@@ -270,11 +271,11 @@ pub fn local_sync<DC: DursConfTrait>(profile_path: PathBuf, conf: &DC, sync_opts
let currency_params = unwrap!(currency_params);
// Push block median_time in blocks_not_expiring
- blocks_not_expiring.push_back(block_doc.median_time);
+ blocks_not_expiring.push_back(block_doc.common_time());
// Get blocks_expiring
let mut blocks_expiring = Vec::new();
while blocks_not_expiring.front().copied()
- < Some(block_doc.median_time - currency_params.sig_validity)
+ < Some(block_doc.common_time() - currency_params.sig_validity)
{
last_block_expiring += 1;
blocks_expiring.push(BlockNumber(last_block_expiring as u32));
diff --git a/lib/modules/ws2p-v1-legacy/src/lib.rs b/lib/modules/ws2p-v1-legacy/src/lib.rs
index 45c14d51..d2ee5314 100644
--- a/lib/modules/ws2p-v1-legacy/src/lib.rs
+++ b/lib/modules/ws2p-v1-legacy/src/lib.rs
@@ -878,7 +878,7 @@ mod tests {
use super::*;
use crate::ws_connections::requests::sent::network_request_to_json;
use crate::ws_connections::requests::*;
- use dubp_documents::documents::block::BlockDocument;
+ use dubp_documents::documents::block::{BlockDocument, BlockDocumentTrait};
use dubp_documents::parsers::blocks::parse_json_block_from_serde_value;
use dubp_documents::BlockNumber;
@@ -1028,19 +1028,19 @@ mod tests {
}
],
});
- let mut block: BlockDocument = parse_json_block_from_serde_value(&json_block)
+ let block: BlockDocument = parse_json_block_from_serde_value(&json_block)
.expect("Fail to parse test json block !");
assert_eq!(
block
- .inner_hash
+ .inner_hash()
.expect("Try to get inner_hash of an uncompleted or reduce block !")
.to_hex(),
"61F02B1A6AE2E4B9A1FD66CE673258B4B21C0076795571EE3C9DC440DD06C46C"
);
- block.compute_hash();
+ //block.generate_hash();
assert_eq!(
block
- .hash
+ .hash()
.expect("Try to get hash of an uncompleted or reduce block !")
.0
.to_hex(),
diff --git a/lib/modules/ws2p-v1-legacy/src/serializers/block.rs b/lib/modules/ws2p-v1-legacy/src/serializers/block.rs
index a896d954..95c8afe9 100644
--- a/lib/modules/ws2p-v1-legacy/src/serializers/block.rs
+++ b/lib/modules/ws2p-v1-legacy/src/serializers/block.rs
@@ -16,9 +16,17 @@
//! Sub-module that serialize BlockDocument into WS2Pv1 json format
use super::IntoWS2Pv1Json;
-use dubp_documents::documents::block::BlockDocumentStringified;
+use dubp_documents::documents::block::{BlockDocumentStringified, BlockDocumentV10Stringified};
impl IntoWS2Pv1Json for BlockDocumentStringified {
+ fn into_ws2p_v1_json(self) -> serde_json::Value {
+ match self {
+ BlockDocumentStringified::V10(block_str_v10) => block_str_v10.into_ws2p_v1_json(),
+ }
+ }
+}
+
+impl IntoWS2Pv1Json for BlockDocumentV10Stringified {
fn into_ws2p_v1_json(self) -> serde_json::Value {
let actives = self
.actives
diff --git a/lib/tests-tools/documents-tests-tools/src/mocks/mod.rs b/lib/tests-tools/documents-tests-tools/src/mocks/mod.rs
index f00c42fe..18a189ae 100644
--- a/lib/tests-tools/documents-tests-tools/src/mocks/mod.rs
+++ b/lib/tests-tools/documents-tests-tools/src/mocks/mod.rs
@@ -17,7 +17,7 @@
pub mod identity;
-use dubp_documents::documents::block::BlockDocument;
+use dubp_documents::documents::block::{BlockDocument, BlockDocumentV10};
use dubp_documents::*;
use dup_crypto::hashs::Hash;
use dup_currency_params::CurrencyName;
@@ -35,10 +35,10 @@ pub fn generate_blockstamps(n: usize) -> Vec<Blockstamp> {
}
/// Generate n empty timed block document
-pub fn gen_empty_timed_blocks(n: usize, time_step: u64) -> Vec<BlockDocument> {
+pub fn gen_empty_timed_blocks_v10(n: usize, time_step: u64) -> Vec<BlockDocument> {
(0..n)
.map(|i| {
- gen_empty_timed_block(
+ BlockDocument::V10(gen_empty_timed_block_v10(
Blockstamp {
id: BlockNumber(i as u32),
hash: BlockHash(dup_crypto_tests_tools::mocks::hash_from_byte(
@@ -51,19 +51,19 @@ pub fn gen_empty_timed_blocks(n: usize, time_step: u64) -> Vec<BlockDocument> {
} else {
dup_crypto_tests_tools::mocks::hash_from_byte(((i - 1) % 255) as u8)
},
- )
+ ))
})
.collect()
}
/// Generate empty timed block document
/// (usefull for tests that only need blockstamp and median_time fields)
-pub fn gen_empty_timed_block(
+pub fn gen_empty_timed_block_v10(
blockstamp: Blockstamp,
time: u64,
previous_hash: Hash,
-) -> BlockDocument {
- BlockDocument {
+) -> BlockDocumentV10 {
+ BlockDocumentV10 {
version: 10,
nonce: 0,
number: blockstamp.id,
@@ -93,6 +93,5 @@ pub fn gen_empty_timed_block(
certifications: vec![],
transactions: vec![],
inner_hash: None,
- inner_hash_and_nonce_str: "".to_owned(),
}
}
diff --git a/lib/tools/currency-params/src/lib.rs b/lib/tools/currency-params/src/lib.rs
index e566fdc7..fd20b2e6 100644
--- a/lib/tools/currency-params/src/lib.rs
+++ b/lib/tools/currency-params/src/lib.rs
@@ -46,6 +46,12 @@ impl Display for CurrencyName {
}
}
+impl From<&str> for CurrencyName {
+ fn from(s: &str) -> Self {
+ CurrencyName(s.to_owned())
+ }
+}
+
#[derive(Debug, Copy, Clone)]
/// Currency parameters
pub struct CurrencyParameters {
diff --git a/lib/tools/documents/src/documents/block.rs b/lib/tools/documents/src/documents/block.rs
index ebac6bcb..f9ded4b7 100644
--- a/lib/tools/documents/src/documents/block.rs
+++ b/lib/tools/documents/src/documents/block.rs
@@ -1,4 +1,4 @@
-// Copyright (C) 2018 The Duniter Project Developers.
+// Copyright (C) 2018 The Durs Project Developers.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
@@ -15,922 +15,236 @@
//! Wrappers around Block document.
-use dup_crypto::hashs::Hash;
-use dup_crypto::keys::*;
-use dup_currency_params::genesis_block_params::v10::BlockV10Parameters;
-use dup_currency_params::CurrencyName;
-use durs_common_tools::fatal_error;
-use std::ops::Deref;
-use unwrap::unwrap;
+pub mod v10;
-use crate::blockstamp::Blockstamp;
-use crate::documents::certification::CertificationDocument;
-use crate::documents::identity::IdentityDocument;
-use crate::documents::membership::MembershipDocument;
-use crate::documents::revocation::RevocationDocument;
-use crate::documents::transaction::TransactionDocument;
-use crate::documents::*;
-use crate::text_document_traits::*;
+pub use v10::{BlockDocumentV10, BlockDocumentV10Stringified};
-/// Store a transaction document or just its hash.
-#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-pub enum TxDocOrTxHash {
- /// Transaction document
- TxDoc(Box<TransactionDocument>),
- /// transaction hash
- TxHash(Hash),
-}
-
-impl TxDocOrTxHash {
- /// Lightens the TxDocOrTxHash (for example to store it while minimizing the space required)
- /// lightening consists in transforming the document by its hash.
- pub fn reduce(&self) -> TxDocOrTxHash {
- if let TxDocOrTxHash::TxDoc(ref tx_doc) = self {
- let tx_doc = tx_doc.deref();
- if let Some(ref hash) = tx_doc.get_hash_opt() {
- TxDocOrTxHash::TxHash(*hash)
- } else {
- TxDocOrTxHash::TxHash(tx_doc.clone().compute_hash())
- }
- } else {
- self.clone()
- }
- }
- /// Get TxDoc variant
- pub fn unwrap_doc(&self) -> TransactionDocument {
- if let TxDocOrTxHash::TxDoc(ref tx_doc) = self {
- tx_doc.deref().clone()
- } else {
- fatal_error!("Try to unwrap_doc() in a TxHash() variant of TxDocOrTxHash !")
- }
- }
-}
+use crate::blockstamp::Blockstamp;
+use crate::{BlockHash, BlockNumber, Document, ToStringObject};
+use dup_crypto::hashs::Hash;
+use dup_crypto::keys::{PrivKey, PubKey, PublicKey};
/// Wrap a Block document.
///
/// Must be created by parsing a text document or using a builder.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
-pub struct BlockDocument {
- /// Version
- pub version: u32,
- /// Nonce
- pub nonce: u64,
- /// number
- pub number: BlockNumber,
- /// Minimal proof of work difficulty
- pub pow_min: usize,
- /// Local time of the block issuer
- pub time: u64,
- /// Average time
- pub median_time: u64,
- /// Members count
- pub members_count: usize,
- /// Monetary mass
- pub monetary_mass: usize,
- /// Unit base (power of ten)
- pub unit_base: usize,
- /// Number of compute members in the current frame
- pub issuers_count: usize,
- /// Current frame size (in blocks)
- pub issuers_frame: isize,
- /// Current frame variation buffer
- pub issuers_frame_var: isize,
- /// Currency.
- pub currency: CurrencyName,
- /// Document issuer (there should be only one).
- pub issuers: Vec<PubKey>,
- /// Document signature (there should be only one).
- /// This vector is empty, when the block is generated but the proof of work has not yet started
- pub signatures: Vec<Sig>,
- /// The hash is None, when the block is generated but the proof of work has not yet started
- pub hash: Option<BlockHash>,
- /// Currency parameters (only in genesis block)
- pub parameters: Option<BlockV10Parameters>,
- /// Hash of the previous block
- pub previous_hash: Option<Hash>,
- /// Issuer of the previous block
- pub previous_issuer: Option<PubKey>,
- /// Hash of the deterministic content of the block
- pub inner_hash: Option<Hash>,
- /// Amount of new dividend created at this block, None if no dividend is created at this block
- pub dividend: Option<usize>,
- /// Identities
- pub identities: Vec<IdentityDocument>,
- /// joiners
- pub joiners: Vec<MembershipDocument>,
- /// Actives (=renewals)
- pub actives: Vec<MembershipDocument>,
- /// Leavers
- pub leavers: Vec<MembershipDocument>,
- /// Revokeds
- pub revoked: Vec<TextDocumentFormat<RevocationDocument>>,
- /// Excludeds
- pub excluded: Vec<PubKey>,
- /// Certifications
- pub certifications: Vec<TextDocumentFormat<CertificationDocument>>,
- /// Transactions
- pub transactions: Vec<TxDocOrTxHash>,
- /// Part to sign
- pub inner_hash_and_nonce_str: String,
+pub enum BlockDocument {
+ V10(BlockDocumentV10),
}
-impl BlockDocument {
- /// Return previous blockstamp
- pub fn previous_blockstamp(&self) -> Blockstamp {
- if self.number.0 > 0 {
- Blockstamp {
- id: BlockNumber(self.number.0 - 1),
- hash: BlockHash(unwrap!(self.previous_hash)),
- }
- } else {
- Blockstamp::default()
- }
- }
- /// Compute inner hash
- pub fn compute_inner_hash(&mut self) {
- self.inner_hash = Some(Hash::compute_str(&self.generate_compact_inner_text()));
- }
+pub trait BlockDocumentTrait {
+ /// Common time in block (also known as 'blockchain time')
+ fn common_time(&self) -> u64;
+ /// Compute hash
+ fn compute_hash(&self) -> BlockHash;
/// Compute inner hash
- pub fn verify_inner_hash(&self) -> bool {
- match self.inner_hash {
- Some(inner_hash) => {
- inner_hash == Hash::compute_str(&self.generate_compact_inner_text())
- }
- None => false,
- }
- }
- // Generate the character string that will be hashed
- fn generate_will_hashed_string(&self) -> String {
- format!(
- "InnerHash: {}\nNonce: {}\n",
- self.inner_hash
- .expect("Try to get inner_hash of an uncompleted or reduce block !")
- .to_hex(),
- self.nonce
- )
- }
+ fn compute_inner_hash(&self) -> Hash {
+ Hash::compute_str(&self.generate_compact_inner_text())
+ }
+ /// Compute the character string that will be hashed
+ fn compute_will_hashed_string(&self) -> String;
+ /// Compute the character string that will be signed
+ fn compute_will_signed_string(&self) -> String;
+ /// Get current frame size (in blocks)
+ fn current_frame_size(&self) -> usize;
+ /// Generate compact inner text (for compute inner_hash)
+ fn generate_compact_inner_text(&self) -> String;
+ /// Compute hash and save it in document
+ fn generate_hash(&mut self);
+ /// Compute inner hash and save it in document
+ fn generate_inner_hash(&mut self);
+ /// Get block hash
+ fn hash(&self) -> Option<BlockHash>;
+ /// Increment nonce
+ fn increment_nonce(&mut self);
+ /// Get block inner hash
+ fn inner_hash(&self) -> Option<Hash>;
+ /// Get number of compute members in the current frame
+ fn issuers_count(&self) -> usize;
+ /// Get block number
+ fn number(&self) -> BlockNumber;
+ /// Get previous hash
+ fn previous_hash(&self) -> Option<Hash>;
+ /// Get previous blockstamp
+ fn previous_blockstamp(&self) -> Blockstamp;
+ /// Lightens the block (for example to store it while minimizing the space required)
+ fn reduce(&mut self);
+ /// Verify inner hash
+ fn verify_inner_hash(&self) -> bool;
/// Verify block hash
- pub fn verify_hash(&self) -> bool {
- match self.hash {
- Some(hash) => {
- let datas = format!(
- "{}{}\n",
- self.generate_will_hashed_string(),
- self.signatures[0]
- );
- let expected_hash = BlockHash(Hash::compute_str(&datas));
- if hash == expected_hash {
- true
- } else {
- warn!(
- "Block #{} have invalid hash (expected='{}', actual='{}', datas='{}').",
- self.number.0, expected_hash, hash, datas
- );
- false
- }
- }
- None => false,
+ fn verify_hash(&self) -> bool;
+ /// Sign block
+ fn sign(&mut self, privkey: PrivKey);
+}
+
+impl BlockDocumentTrait for BlockDocument {
+ #[inline]
+ fn compute_hash(&self) -> BlockHash {
+ match self {
+ BlockDocument::V10(block) => block.compute_hash(),
}
}
- /// Fill inner_hash_and_nonce_str
- pub fn fill_inner_hash_and_nonce_str(&mut self, new_nonce: Option<u64>) {
- if let Some(new_nonce) = new_nonce {
- self.nonce = new_nonce;
+ #[inline]
+ fn compute_will_hashed_string(&self) -> String {
+ match self {
+ BlockDocument::V10(block) => block.compute_will_hashed_string(),
}
- self.inner_hash_and_nonce_str = self.generate_will_hashed_string();
- }
- /// Sign block
- pub fn sign(&mut self, privkey: PrivKey) {
- self.fill_inner_hash_and_nonce_str(None);
- self.signatures = vec![privkey.sign(self.inner_hash_and_nonce_str.as_bytes())];
- }
- /// Compute hash
- pub fn compute_hash(&mut self) {
- self.hash = Some(BlockHash(Hash::compute_str(&format!(
- "{}{}\n",
- self.generate_will_hashed_string(),
- self.signatures[0]
- ))));
}
- /// Lightens the block (for example to store it while minimizing the space required)
- pub fn reduce(&mut self) {
- //self.hash = None;
- self.inner_hash = None;
- self.inner_hash_and_nonce_str = String::with_capacity(0);
- for i in &mut self.identities {
- i.reduce();
- }
- for i in &mut self.joiners {
- i.reduce();
+ #[inline]
+ fn compute_will_signed_string(&self) -> String {
+ match self {
+ BlockDocument::V10(block) => block.compute_will_signed_string(),
}
- for i in &mut self.actives {
- i.reduce();
+ }
+ #[inline]
+ fn current_frame_size(&self) -> usize {
+ match self {
+ BlockDocument::V10(block) => block.current_frame_size(),
}
- for i in &mut self.leavers {
- i.reduce();
+ }
+ #[inline]
+ fn generate_compact_inner_text(&self) -> String {
+ match self {
+ BlockDocument::V10(block) => block.generate_compact_inner_text(),
}
- for i in &mut self.transactions {
- i.reduce();
+ }
+ #[inline]
+ fn generate_hash(&mut self) {
+ match self {
+ BlockDocument::V10(block) => block.generate_hash(),
}
}
- /// Generate compact inner text (for compute inner_hash)
- pub fn generate_compact_inner_text(&self) -> String {
- let mut identities_str = String::from("");
- for identity in self.identities.clone() {
- identities_str.push_str("\n");
- identities_str.push_str(&identity.generate_compact_text());
+ #[inline]
+ fn generate_inner_hash(&mut self) {
+ match self {
+ BlockDocument::V10(block) => block.generate_inner_hash(),
}
- let mut joiners_str = String::from("");
- for joiner in self.joiners.clone() {
- joiners_str.push_str("\n");
- joiners_str.push_str(&joiner.generate_compact_text());
+ }
+ #[inline]
+ fn hash(&self) -> Option<BlockHash> {
+ match self {
+ BlockDocument::V10(block) => block.hash(),
}
- let mut actives_str = String::from("");
- for active in self.actives.clone() {
- actives_str.push_str("\n");
- actives_str.push_str(&active.generate_compact_text());
+ }
+ #[inline]
+ fn increment_nonce(&mut self) {
+ match self {
+ BlockDocument::V10(block) => block.increment_nonce(),
}
- let mut leavers_str = String::from("");
- for leaver in self.leavers.clone() {
- leavers_str.push_str("\n");
- leavers_str.push_str(&leaver.generate_compact_text());
+ }
+ #[inline]
+ fn inner_hash(&self) -> Option<Hash> {
+ match self {
+ BlockDocument::V10(block) => block.inner_hash(),
}
- let mut identities_str = String::from("");
- for identity in self.identities.clone() {
- identities_str.push_str("\n");
- identities_str.push_str(&identity.generate_compact_text());
+ }
+ #[inline]
+ fn issuers_count(&self) -> usize {
+ match self {
+ BlockDocument::V10(block) => block.issuers_count(),
}
- let mut revokeds_str = String::from("");
- for revocation in self.revoked.clone() {
- revokeds_str.push_str("\n");
- revokeds_str.push_str(&revocation.as_compact_text());
+ }
+ #[inline]
+ fn common_time(&self) -> u64 {
+ match self {
+ BlockDocument::V10(block) => block.common_time(),
}
- let mut excludeds_str = String::from("");
- for exclusion in self.excluded.clone() {
- excludeds_str.push_str("\n");
- excludeds_str.push_str(&exclusion.to_string());
+ }
+ #[inline]
+ fn number(&self) -> BlockNumber {
+ match self {
+ BlockDocument::V10(block) => block.number(),
}
- let mut certifications_str = String::from("");
- for certification in self.certifications.clone() {
- certifications_str.push_str("\n");
- certifications_str.push_str(&certification.as_compact_text());
+ }
+ #[inline]
+ fn previous_blockstamp(&self) -> Blockstamp {
+ match self {
+ BlockDocument::V10(block) => block.previous_blockstamp(),
}
- let mut transactions_str = String::from("");
- for transaction in self.transactions.clone() {
- if let TxDocOrTxHash::TxDoc(transaction) = transaction {
- transactions_str.push_str("\n");
- transactions_str.push_str(&transaction.deref().generate_compact_text());
- }
+ }
+ #[inline]
+ fn previous_hash(&self) -> Option<Hash> {
+ match self {
+ BlockDocument::V10(block) => block.previous_hash(),
}
- let mut dividend_str = String::from("");
- if let Some(dividend) = self.dividend {
- if dividend > 0 {
- dividend_str.push_str("UniversalDividend: ");
- dividend_str.push_str(÷nd.to_string());
- dividend_str.push_str("\n");
- }
+ }
+ #[inline]
+ fn reduce(&mut self) {
+ match self {
+ BlockDocument::V10(block) => block.reduce(),
}
- let mut parameters_str = String::from("");
- if let Some(params) = self.parameters {
- parameters_str.push_str("Parameters: ");
- parameters_str.push_str(¶ms.to_string());
- parameters_str.push_str("\n");
+ }
+ #[inline]
+ fn verify_inner_hash(&self) -> bool {
+ match self {
+ BlockDocument::V10(block) => block.verify_inner_hash(),
}
- let mut previous_hash_str = String::from("");
- if self.number.0 > 0 {
- previous_hash_str.push_str("PreviousHash: ");
- previous_hash_str.push_str(&unwrap!(self.previous_hash).to_string());
- previous_hash_str.push_str("\n");
+ }
+ #[inline]
+ fn verify_hash(&self) -> bool {
+ match self {
+ BlockDocument::V10(block) => block.verify_hash(),
}
- let mut previous_issuer_str = String::from("");
- if self.number.0 > 0 {
- previous_issuer_str.push_str("PreviousIssuer: ");
- previous_issuer_str.push_str(
- &self
- .previous_issuer
- .expect("No genesis block must have previous issuer")
- .to_string(),
- );
- previous_issuer_str.push_str("\n");
+ }
+ #[inline]
+ fn sign(&mut self, privkey: PrivKey) {
+ match self {
+ BlockDocument::V10(block) => block.sign(privkey),
}
- format!(
- "Version: {version}
-Type: Block
-Currency: {currency}
-Number: {block_number}
-PoWMin: {pow_min}
-Time: {time}
-MedianTime: {median_time}
-{dividend}UnitBase: {unit_base}
-Issuer: {issuer}
-IssuersFrame: {issuers_frame}
-IssuersFrameVar: {issuers_frame_var}
-DifferentIssuersCount: {issuers_count}
-{parameters}{previous_hash}{previous_issuer}MembersCount: {members_count}
-Identities:{identities}
-Joiners:{joiners}
-Actives:{actives}
-Leavers:{leavers}
-Revoked:{revoked}
-Excluded:{excluded}
-Certifications:{certifications}
-Transactions:{transactions}
-",
- version = self.version,
- currency = self.currency,
- block_number = self.number,
- pow_min = self.pow_min,
- time = self.time,
- median_time = self.median_time,
- dividend = dividend_str,
- unit_base = self.unit_base,
- issuer = self.issuers[0],
- issuers_frame = self.issuers_frame,
- issuers_frame_var = self.issuers_frame_var,
- issuers_count = self.issuers_count,
- parameters = parameters_str,
- previous_hash = previous_hash_str,
- previous_issuer = previous_issuer_str,
- members_count = self.members_count,
- identities = identities_str,
- joiners = joiners_str,
- actives = actives_str,
- leavers = leavers_str,
- revoked = revokeds_str,
- excluded = excludeds_str,
- certifications = certifications_str,
- transactions = transactions_str,
- )
}
}
impl Document for BlockDocument {
type PublicKey = PubKey;
- type CurrencyType = str;
fn version(&self) -> u16 {
- 10
+ match self {
+ BlockDocument::V10(_) => 10u16,
+ }
}
fn currency(&self) -> &str {
- &self.currency.0
+ match self {
+ BlockDocument::V10(block) => block.currency(),
+ }
}
fn blockstamp(&self) -> Blockstamp {
- Blockstamp {
- id: self.number,
- hash: self
- .hash
- .expect("Fatal error : try to get blockstamp of an uncomplete or reduce block !"),
+ match self {
+ BlockDocument::V10(block) => block.blockstamp(),
}
}
- fn issuers(&self) -> &Vec<PubKey> {
- &self.issuers
+ fn issuers(&self) -> &Vec<Self::PublicKey> {
+ match self {
+ BlockDocument::V10(block) => block.issuers(),
+ }
}
- fn signatures(&self) -> &Vec<Sig> {
- &self.signatures
+ fn signatures(&self) -> &Vec<<Self::PublicKey as PublicKey>::Signature> {
+ match self {
+ BlockDocument::V10(block) => block.signatures(),
+ }
}
fn as_bytes(&self) -> &[u8] {
- self.inner_hash_and_nonce_str.as_bytes()
- }
-}
-
-impl CompactTextDocument for BlockDocument {
- fn as_compact_text(&self) -> String {
- let compact_inner_text = self.generate_compact_inner_text();
- format!(
- "{}InnerHash: {}\nNonce: ",
- compact_inner_text,
- self.inner_hash
- .expect("Try to get inner_hash of an uncompleted or reduce block !")
- .to_hex()
- )
- }
-}
-
-impl TextDocument for BlockDocument {
- type CompactTextDocument_ = BlockDocument;
-
- fn as_text(&self) -> &str {
- fatal_error!(
- "Dev error: function not implemented. Please use to_compact_document() instead"
- );
- }
-
- fn to_compact_document(&self) -> Self::CompactTextDocument_ {
- self.clone()
- }
-}
-
-impl IntoSpecializedDocument<DUBPDocument> for BlockDocument {
- fn into_specialized(self) -> DUBPDocument {
- DUBPDocument::Block(Box::new(self))
+ match self {
+ BlockDocument::V10(block) => block.as_bytes(),
+ }
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
-pub struct BlockDocumentStringified {
- /// Version
- pub version: u64,
- /// Nonce
- pub nonce: u64,
- /// number
- pub number: u64,
- /// Minimal proof of work difficulty
- pub pow_min: u64,
- /// Local time of the block issuer
- pub time: u64,
- /// Average time
- pub median_time: u64,
- /// Members count
- pub members_count: u64,
- /// Monetary mass
- pub monetary_mass: u64,
- /// Unit base (power of ten)
- pub unit_base: u64,
- /// Number of compute members in the current frame
- pub issuers_count: u64,
- /// Current frame size (in blocks)
- pub issuers_frame: i64,
- /// Current frame variation buffer
- pub issuers_frame_var: i64,
- /// Currency.
- pub currency: String,
- /// Document issuer (there should be only one).
- pub issuers: Vec<String>,
- /// Document signature (there should be only one).
- /// This vector is empty, when the block is generated but the proof of work has not yet started
- pub signatures: Vec<String>,
- /// The hash is None, when the block is generated but the proof of work has not yet started
- pub hash: Option<String>,
- /// Currency parameters (only in genesis block)
- pub parameters: Option<String>,
- /// Hash of the previous block
- pub previous_hash: Option<String>,
- /// Issuer of the previous block
- pub previous_issuer: Option<String>,
- /// Hash of the deterministic content of the block
- pub inner_hash: Option<String>,
- /// Amount of new dividend created at this block, None if no dividend is created at this block
- pub dividend: Option<u64>,
- /// Identities
- pub identities: Vec<IdentityStringDocument>,
- /// joiners
- pub joiners: Vec<MembershipStringDocument>,
- /// Actives (=renewals)
- pub actives: Vec<MembershipStringDocument>,
- /// Leavers
- pub leavers: Vec<MembershipStringDocument>,
- /// Revokeds
- pub revoked: Vec<CompactRevocationStringDocument>,
- /// Excludeds
- pub excluded: Vec<String>,
- /// Certifications
- pub certifications: Vec<CompactCertificationStringDocument>,
- /// Transactions
- pub transactions: Vec<TransactionDocumentStringified>,
+pub enum BlockDocumentStringified {
+ V10(BlockDocumentV10Stringified),
}
impl ToStringObject for BlockDocument {
type StringObject = BlockDocumentStringified;
- /// Transforms an object into a json object
- fn to_string_object(&self) -> BlockDocumentStringified {
- BlockDocumentStringified {
- version: u64::from(self.version),
- nonce: self.nonce,
- number: u64::from(self.number.0),
- pow_min: self.pow_min as u64,
- time: self.time,
- median_time: self.median_time,
- members_count: self.members_count as u64,
- monetary_mass: self.monetary_mass as u64,
- unit_base: self.unit_base as u64,
- issuers_count: self.issuers_count as u64,
- issuers_frame: self.issuers_frame as i64,
- issuers_frame_var: self.issuers_frame_var as i64,
- currency: self.currency.to_string(),
- issuers: self.issuers.iter().map(ToString::to_string).collect(),
- signatures: self.signatures.iter().map(ToString::to_string).collect(),
- hash: self.hash.map(|hash| hash.to_string()),
- parameters: self.parameters.map(|parameters| parameters.to_string()),
- previous_hash: self.previous_hash.map(|hash| hash.to_string()),
- previous_issuer: self.previous_issuer.map(|p| p.to_string()),
- inner_hash: self.inner_hash.map(|hash| hash.to_string()),
- dividend: self.dividend.map(|dividend| dividend as u64),
- identities: self
- .identities
- .iter()
- .map(ToStringObject::to_string_object)
- .collect(),
- joiners: self
- .joiners
- .iter()
- .map(ToStringObject::to_string_object)
- .collect(),
- actives: self
- .actives
- .iter()
- .map(ToStringObject::to_string_object)
- .collect(),
- leavers: self
- .leavers
- .iter()
- .map(ToStringObject::to_string_object)
- .collect(),
- revoked: self
- .revoked
- .iter()
- .map(|revocation_doc| match revocation_doc {
- TextDocumentFormat::Complete(complete_revoc_doc) => {
- complete_revoc_doc.to_compact_document().to_string_object()
- }
- TextDocumentFormat::Compact(compact_revoc_doc) => {
- compact_revoc_doc.to_string_object()
- }
- })
- .collect(),
- excluded: self.excluded.iter().map(ToString::to_string).collect(),
- certifications: self
- .certifications
- .iter()
- .map(|cert_doc| match cert_doc {
- TextDocumentFormat::Complete(complete_cert_doc) => {
- complete_cert_doc.to_compact_document().to_string_object()
- }
- TextDocumentFormat::Compact(compact_cert_doc) => {
- compact_cert_doc.to_string_object()
- }
- })
- .collect(),
- transactions: self
- .transactions
- .iter()
- .map(|tx_doc_or_tx_hash| match tx_doc_or_tx_hash {
- TxDocOrTxHash::TxDoc(tx_doc) => tx_doc.to_string_object(),
- TxDocOrTxHash::TxHash(_) => {
- fatal_error!("Try to stringify block without their tx documents")
- }
- })
- .collect(),
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::certification::CertificationDocumentParser;
- use super::transaction::TransactionDocumentParser;
- use super::*;
- use crate::{Document, VerificationResult};
-
- #[test]
- fn generate_and_verify_empty_block() {
- let mut block = BlockDocument {
- nonce: 100_010_200_000_006_940,
- version: 10,
- number: BlockNumber(174_260),
- pow_min: 68,
- time: 1_525_296_873,
- median_time: 1_525_292_577,
- members_count: 33,
- monetary_mass: 15_633_687,
- unit_base: 0,
- issuers_count: 8,
- issuers_frame: 41,
- issuers_frame_var: 0,
- currency: CurrencyName(String::from("g1-test")),
- issuers: vec![PubKey::Ed25519(ed25519::PublicKey::from_base58("39Fnossy1GrndwCnAXGDw3K5UYXhNXAFQe7yhYZp8ELP").unwrap())],
- signatures: vec![Sig::Ed25519(ed25519::Signature::from_base64("lqXrNOopjM39oM7hgB7Vq13uIohdCuLlhh/q8RVVEZ5UVASphow/GXikCdhbWID19Bn0XrXzTbt/R7akbE9xAg==").unwrap())],
- hash: None,
- parameters: None,
- previous_hash: Some(Hash::from_hex("0000A7D4361B9EBF4CE974A521149A73E8A5DE9B73907AB3BC918726AED7D40A").expect("fail to parse previous_hash")),
- previous_issuer: Some(PubKey::Ed25519(ed25519::PublicKey::from_base58("EPKuZA1Ek5y8S1AjAmAPtGrVCMFqUGzUEAa7Ei62CY2L").unwrap())),
- inner_hash: None,
- dividend: None,
- identities: Vec::new(),
- joiners: Vec::new(),
- actives: Vec::new(),
- leavers: Vec::new(),
- revoked: Vec::new(),
- excluded: Vec::new(),
- certifications: Vec::new(),
- transactions: Vec::new(),
- inner_hash_and_nonce_str: String::new(),
- };
- // test inner_hash computation
- block.compute_inner_hash();
- println!("{}", block.generate_compact_text());
- assert_eq!(
- block
- .inner_hash
- .expect("Try to get inner_hash of an uncompleted or reduce block !")
- .to_hex(),
- "58E4865A47A46E0DF1449AABC449B5406A12047C413D61B5E17F86BE6641E7B0"
- );
- // Test signature validity
- block.fill_inner_hash_and_nonce_str(Some(100_010_200_000_006_940));
- assert_eq!(block.verify_signatures(), VerificationResult::Valid());
- // Test hash computation
- block.compute_hash();
- assert_eq!(
- block
- .hash
- .expect("Try to get hash of an uncompleted or reduce block !")
- .0
- .to_hex(),
- "00002EE584F36C15D3EB21AAC78E0896C75EF9070E73B4EC33BFA2C3D561EEB2"
- );
- }
- #[test]
- fn generate_and_verify_block() {
- let cert1 = CertificationDocumentParser::parse("Version: 10
-Type: Certification
-Currency: g1
-Issuer: 6TAzLWuNcSqgNDNpAutrKpPXcGJwy1ZEMeVvZSZNs2e3
-IdtyIssuer: CYPsYTdt87Tx6cCiZs9KD4jqPgYxbcVEqVZpRgJ9jjoV
-IdtyUniqueID: PascaleM
-IdtyTimestamp: 97401-0000003821911909F98519CC773D2D3E5CFE3D5DBB39F4F4FF33B96B4D41800E
-IdtySignature: QncUVXxZ2NfARjdJOn6luILvDuG1NuK9qSoaU4CST2Ij8z7oeVtEgryHl+EXOjSe6XniALsCT0gU8wtadcA/Cw==
-CertTimestamp: 106669-000003682E6FE38C44433DCE92E8B2A26C69B6D7867A2BAED231E788DDEF4251
-UmseG2XKNwKcY8RFi6gUCT91udGnnNmSh7se10J1jeRVlwf+O2Tyb2Cccot9Dt7BO4+Kx2P6vFJB3oVGGHMxBA==").expect("Fail to parse cert1");
-
- let tx1 = TransactionDocumentParser::parse("Version: 10
-Type: Transaction
-Currency: g1
-Blockstamp: 107982-000001242F6DA51C06A915A96C58BAA37AB3D1EB51F6E1C630C707845ACF764B
-Locktime: 0
-Issuers:
-8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3
-Inputs:
-1002:0:D:8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3:106345
-Unlocks:
-0:SIG(0)
-Outputs:
-1002:0:SIG(CitdnuQgZ45tNFCagay7Wh12gwwHM8VLej1sWmfHWnQX)
-Comment: DU symbolique pour demander le codage de nouvelles fonctionnalites cf. https://forum.monnaie-libre.fr/t/creer-de-nouvelles-fonctionnalites-dans-cesium-les-autres-applications/2025 Merci
-T0LlCcbIn7xDFws48H8LboN6NxxwNXXTovG4PROLf7tkUAueHFWjfwZFKQXeZEHxfaL1eYs3QspGtLWUHPRVCQ==").expect("Fail to parse tx1");
-
- let tx2 = TransactionDocumentParser::parse("Version: 10
-Type: Transaction
-Currency: g1
-Blockstamp: 107982-000001242F6DA51C06A915A96C58BAA37AB3D1EB51F6E1C630C707845ACF764B
-Locktime: 0
-Issuers:
-8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3
-Inputs:
-1002:0:D:8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3:106614
-Unlocks:
-0:SIG(0)
-Outputs:
-1002:0:SIG(78ZwwgpgdH5uLZLbThUQH7LKwPgjMunYfLiCfUCySkM8)
-Comment: DU symbolique pour demander le codage de nouvelles fonctionnalites cf. https://forum.monnaie-libre.fr/t/creer-de-nouvelles-fonctionnalites-dans-cesium-les-autres-applications/2025 Merci
-a9PHPuSfw7jW8FRQHXFsGi/bnLjbtDnTYvEVgUC9u0WlR7GVofa+Xb+l5iy6NwuEXiwvueAkf08wPVY8xrNcCg==").expect("Fail to parse tx2");
-
- let mut block = BlockDocument {
- nonce: 0,
- version: 10,
- number: BlockNumber(107_984),
- pow_min: 88,
- time: 1_522_685_861,
- median_time: 1522683184,
- members_count: 896,
- monetary_mass: 140_469_765,
- unit_base: 0,
- issuers_count: 42,
- issuers_frame: 211,
- issuers_frame_var: 0,
- currency: CurrencyName(String::from("g1")),
- issuers: vec![PubKey::Ed25519(ed25519::PublicKey::from_base58("DA4PYtXdvQqk1nCaprXH52iMsK5Ahxs1nRWbWKLhpVkQ").unwrap())],
- signatures: vec![Sig::Ed25519(ed25519::Signature::from_base64("92id58VmkhgVNee4LDqBGSm8u/ooHzAD67JM6fhAE/CV8LCz7XrMF1DvRl+eRpmlaVkp6I+Iy8gmZ1WUM5C8BA==").unwrap())],
- hash: None,
- parameters: None,
- previous_hash: Some(Hash::from_hex("000001144968D0C3516BE6225E4662F182E28956AF46DD7FB228E3D0F9413FEB").expect("fail to parse previous_hash")),
- previous_issuer: Some(PubKey::Ed25519(ed25519::PublicKey::from_base58("D3krfq6J9AmfpKnS3gQVYoy7NzGCc61vokteTS8LJ4YH").unwrap())),
- inner_hash: None,
- dividend: None,
- identities: Vec::new(),
- joiners: Vec::new(),
- actives: Vec::new(),
- leavers: Vec::new(),
- revoked: Vec::new(),
- excluded: Vec::new(),
- certifications: vec![TextDocumentFormat::Complete(cert1)],
- transactions: vec![TxDocOrTxHash::TxDoc(Box::new(tx1)), TxDocOrTxHash::TxDoc(Box::new(tx2))],
- inner_hash_and_nonce_str: String::new(),
- };
- // test inner_hash computation
- block.compute_inner_hash();
- println!("{}", block.generate_compact_text());
- assert_eq!(
- block
- .inner_hash
- .expect("Try to get inner_hash of an uncompleted or reduce block !")
- .to_hex(),
- "C8AB69E33ECE2612EADC7AB30D069B1F1A3D8C95EBBFD50DE583AC8E3666CCA1"
- );
- // test generate_compact_text()
- assert_eq!(
- block.generate_compact_text(),
- "Version: 10
-Type: Block
-Currency: g1
-Number: 107984
-PoWMin: 88
-Time: 1522685861
-MedianTime: 1522683184
-UnitBase: 0
-Issuer: DA4PYtXdvQqk1nCaprXH52iMsK5Ahxs1nRWbWKLhpVkQ
-IssuersFrame: 211
-IssuersFrameVar: 0
-DifferentIssuersCount: 42
-PreviousHash: 000001144968D0C3516BE6225E4662F182E28956AF46DD7FB228E3D0F9413FEB
-PreviousIssuer: D3krfq6J9AmfpKnS3gQVYoy7NzGCc61vokteTS8LJ4YH
-MembersCount: 896
-Identities:
-Joiners:
-Actives:
-Leavers:
-Revoked:
-Excluded:
-Certifications:
-6TAzLWuNcSqgNDNpAutrKpPXcGJwy1ZEMeVvZSZNs2e3:CYPsYTdt87Tx6cCiZs9KD4jqPgYxbcVEqVZpRgJ9jjoV:106669:UmseG2XKNwKcY8RFi6gUCT91udGnnNmSh7se10J1jeRVlwf+O2Tyb2Cccot9Dt7BO4+Kx2P6vFJB3oVGGHMxBA==
-Transactions:
-TX:10:1:1:1:1:1:0
-107982-000001242F6DA51C06A915A96C58BAA37AB3D1EB51F6E1C630C707845ACF764B
-8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3
-1002:0:D:8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3:106345
-0:SIG(0)
-1002:0:SIG(CitdnuQgZ45tNFCagay7Wh12gwwHM8VLej1sWmfHWnQX)
-DU symbolique pour demander le codage de nouvelles fonctionnalites cf. https://forum.monnaie-libre.fr/t/creer-de-nouvelles-fonctionnalites-dans-cesium-les-autres-applications/2025 Merci
-T0LlCcbIn7xDFws48H8LboN6NxxwNXXTovG4PROLf7tkUAueHFWjfwZFKQXeZEHxfaL1eYs3QspGtLWUHPRVCQ==
-TX:10:1:1:1:1:1:0
-107982-000001242F6DA51C06A915A96C58BAA37AB3D1EB51F6E1C630C707845ACF764B
-8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3
-1002:0:D:8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3:106614
-0:SIG(0)
-1002:0:SIG(78ZwwgpgdH5uLZLbThUQH7LKwPgjMunYfLiCfUCySkM8)
-DU symbolique pour demander le codage de nouvelles fonctionnalites cf. https://forum.monnaie-libre.fr/t/creer-de-nouvelles-fonctionnalites-dans-cesium-les-autres-applications/2025 Merci
-a9PHPuSfw7jW8FRQHXFsGi/bnLjbtDnTYvEVgUC9u0WlR7GVofa+Xb+l5iy6NwuEXiwvueAkf08wPVY8xrNcCg==
-InnerHash: C8AB69E33ECE2612EADC7AB30D069B1F1A3D8C95EBBFD50DE583AC8E3666CCA1
-Nonce: "
- );
- // Test signature validity
- block.fill_inner_hash_and_nonce_str(Some(10_300_000_018_323));
- assert_eq!(block.verify_signatures(), VerificationResult::Valid());
- // Test hash computation
- block.compute_hash();
- assert_eq!(
- block
- .hash
- .expect("Try to get hash of an uncompleted or reduce block !")
- .0
- .to_hex(),
- "000004F8B84A3590243BA562E5F2BA379F55A0B387C5D6FAC1022DFF7FFE6014"
- );
- }
-
- #[test]
- fn generate_and_verify_block_2() {
- let ms1 = MembershipDocumentParser::parse(
- "Version: 10
-Type: Membership
-Currency: g1
-Issuer: 4VZkro3N7VonygybESHngKUABA6gSrbW77Ktb94zE969
-Block: 165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2
-Membership: IN
-UserID: piaaf31
-CertTS: 74077-0000022816648B2F7801E059F67CCD0C023FF0ED84459D52C70494D74DDCC6F6
-gvaZ1QnJf8FjjRDJ0cYusgpBgQ8r0NqEz39BooH6DtIrgX+WTeXuLSnjZDl35VCBjokvyjry+v0OkTT8FKpABA==",
- )
- .expect("Fail to parse ms1");
-
- let tx1 = TransactionDocumentParser::parse(
- "Version: 10
-Type: Transaction
-Currency: g1
-Blockstamp: 165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2
-Locktime: 0
-Issuers:
-51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2
-Inputs:
-1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:163766
-1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164040
-1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164320
-1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164584
-1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164849
-1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:165118
-1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:165389
-Unlocks:
-0:SIG(0)
-1:SIG(0)
-2:SIG(0)
-3:SIG(0)
-4:SIG(0)
-5:SIG(0)
-6:SIG(0)
-Outputs:
-7000:0:SIG(98wxzS683Tc1WWm1YxpL5WpxS7wBa1mZBccKSsYpaant)
-28:0:SIG(51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2)
-Comment: Panier mixte plus 40 pommes merci
-7o/yIh0BNSAv5pNmHz04uUBl8TuP2s4HRFMtKeGFQfXNYJPUyJTP/dj6hdrgKtJkm5dCfbxT4KRy6wJf+dj1Cw==",
- )
- .expect("Fail to parse tx1");
-
- let tx2 = TransactionDocumentParser::parse(
- "Version: 10
-Type: Transaction
-Currency: g1
-Blockstamp: 165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2
-Locktime: 0
-Issuers:
-3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX
-Inputs:
-1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:148827
-1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149100
-1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149370
-1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149664
-1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149943
-1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:150222
-Unlocks:
-0:SIG(0)
-1:SIG(0)
-2:SIG(0)
-3:SIG(0)
-4:SIG(0)
-5:SIG(0)
-Outputs:
-6000:0:SIG(AopwTfXhj8VqZReFJYGGWnoWnXNj3RgaqFcGGywXpZrD)
-12:0:SIG(3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX)
-Comment: En reglement de tes bons bocaux de fruits et legumes
-nxr4exGrt16jteN9ZX3XZPP9l+X0OUbZ1o/QjE1hbWQNtVU3HhH9SJoEvNj2iVl3gCRr9u2OA9uj9vCyUDyjAg==
-",
- )
- .expect("Fail to parse tx2");
-
- let mut block = BlockDocument {
- nonce: 0,
- version: 10,
- number: BlockNumber(165_647),
- pow_min: 90,
- time: 1_540_633_175,
- median_time: 1_540_627_811,
- members_count: 1402,
- monetary_mass: 386_008_811,
- unit_base: 0,
- issuers_count: 37,
- issuers_frame: 186,
- issuers_frame_var: 0,
- currency: CurrencyName(String::from("g1")),
- issuers: vec![PubKey::Ed25519(ed25519::PublicKey::from_base58("A4pc9Uuk4NXkWG8CibicjjPpEPdiup1mhjMoRWUZsonq").unwrap())],
- signatures: vec![Sig::Ed25519(ed25519::Signature::from_base64("2Z/+9ADdZvHXs19YR8+qDzgfl8WJlBG5PcbFvBG9TOuUJbjAdxhcgxrFrSRIABGWcCrIgLkB805fZVLP8jOjBA==").unwrap())],
- hash: None,
- parameters: None,
- previous_hash: Some(Hash::from_hex("000003E78FA4133F2C13B416F330C8DFB5A41EB87E37190615DB334F2C914A51").expect("fail to parse previous_hash")),
- previous_issuer: Some(PubKey::Ed25519(ed25519::PublicKey::from_base58("8NmGZmGjL1LUgJQRg282yQF7KTdQuRNAg8QfSa2qvd65").unwrap())),
- inner_hash: None,//Some(Hash::from_hex("3B49ECC1475549CFD94CA7B399311548A0FD0EC93C8EDD5670DAA5A958A41846").expect("fail to parse inner_hash")),
- dividend: None,
- identities: vec![],
- joiners: vec![],
- actives: vec![ms1],
- leavers: vec![],
- revoked: vec![],
- excluded: vec![],
- certifications: vec![],
- transactions: vec![TxDocOrTxHash::TxDoc(Box::new(tx1)), TxDocOrTxHash::TxDoc(Box::new(tx2))],
- inner_hash_and_nonce_str: String::new(),
- };
- // test inner_hash computation
- block.compute_inner_hash();
- println!("{}", block.generate_compact_text());
- assert_eq!(
- block
- .inner_hash
- .expect("Try to get inner_hash of an uncompleted or reduce block !")
- .to_hex(),
- "3B49ECC1475549CFD94CA7B399311548A0FD0EC93C8EDD5670DAA5A958A41846"
- );
- // test generate_compact_text()
- let block_compact_text = block.generate_compact_text();
- assert_eq!(
- block_compact_text,
- "Version: 10\nType: Block\nCurrency: g1\nNumber: 165647\nPoWMin: 90\nTime: 1540633175\nMedianTime: 1540627811\nUnitBase: 0\nIssuer: A4pc9Uuk4NXkWG8CibicjjPpEPdiup1mhjMoRWUZsonq\nIssuersFrame: 186\nIssuersFrameVar: 0\nDifferentIssuersCount: 37\nPreviousHash: 000003E78FA4133F2C13B416F330C8DFB5A41EB87E37190615DB334F2C914A51\nPreviousIssuer: 8NmGZmGjL1LUgJQRg282yQF7KTdQuRNAg8QfSa2qvd65\nMembersCount: 1402\nIdentities:\nJoiners:\nActives:\n4VZkro3N7VonygybESHngKUABA6gSrbW77Ktb94zE969:gvaZ1QnJf8FjjRDJ0cYusgpBgQ8r0NqEz39BooH6DtIrgX+WTeXuLSnjZDl35VCBjokvyjry+v0OkTT8FKpABA==:165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2:74077-0000022816648B2F7801E059F67CCD0C023FF0ED84459D52C70494D74DDCC6F6:piaaf31\nLeavers:\nRevoked:\nExcluded:\nCertifications:\nTransactions:\nTX:10:1:7:7:2:1:0\n165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2\n51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:163766\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164040\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164320\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164584\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164849\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:165118\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:165389\n0:SIG(0)\n1:SIG(0)\n2:SIG(0)\n3:SIG(0)\n4:SIG(0)\n5:SIG(0)\n6:SIG(0)\n7000:0:SIG(98wxzS683Tc1WWm1YxpL5WpxS7wBa1mZBccKSsYpaant)\n28:0:SIG(51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2)\nPanier mixte plus 40 pommes merci\n7o/yIh0BNSAv5pNmHz04uUBl8TuP2s4HRFMtKeGFQfXNYJPUyJTP/dj6hdrgKtJkm5dCfbxT4KRy6wJf+dj1Cw==\nTX:10:1:6:6:2:1:0\n165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2\n3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:148827\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149100\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149370\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149664\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149943\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:150222\n0:SIG(0)\n1:SIG(0)\n2:SIG(0)\n3:SIG(0)\n4:SIG(0)\n5:SIG(0)\n6000:0:SIG(AopwTfXhj8VqZReFJYGGWnoWnXNj3RgaqFcGGywXpZrD)\n12:0:SIG(3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX)\nEn reglement de tes bons bocaux de fruits et legumes\nnxr4exGrt16jteN9ZX3XZPP9l+X0OUbZ1o/QjE1hbWQNtVU3HhH9SJoEvNj2iVl3gCRr9u2OA9uj9vCyUDyjAg==\nInnerHash: 3B49ECC1475549CFD94CA7B399311548A0FD0EC93C8EDD5670DAA5A958A41846\nNonce: "
- );
- // Test signature validity
- block.fill_inner_hash_and_nonce_str(Some(10_300_000_090_296));
- assert_eq!(block.verify_signatures(), VerificationResult::Valid());
- // Test hash computation
- block.compute_hash();
- assert_eq!(
- block
- .hash
- .expect("Try to get hash of an uncompleted or reduce block !")
- .0
- .to_hex(),
- "000002026E32A3D649B34968AAF9D03C4F19A5954229C54A801BBB1CD216B230"
- );
+ fn to_string_object(&self) -> Self::StringObject {
+ match self {
+ BlockDocument::V10(block) => BlockDocumentStringified::V10(block.to_string_object()),
+ }
}
}
diff --git a/lib/tools/documents/src/documents/block/v10.rs b/lib/tools/documents/src/documents/block/v10.rs
new file mode 100644
index 00000000..f0ffc6b8
--- /dev/null
+++ b/lib/tools/documents/src/documents/block/v10.rs
@@ -0,0 +1,954 @@
+// Copyright (C) 2018 The Duniter Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+//! Wrappers around Block document v10.
+
+use dup_crypto::hashs::Hash;
+use dup_crypto::keys::*;
+use dup_currency_params::genesis_block_params::v10::BlockV10Parameters;
+use dup_currency_params::CurrencyName;
+use durs_common_tools::fatal_error;
+use std::ops::Deref;
+use unwrap::unwrap;
+
+use super::BlockDocumentTrait;
+use crate::blockstamp::Blockstamp;
+use crate::documents::certification::CertificationDocument;
+use crate::documents::identity::IdentityDocument;
+use crate::documents::membership::MembershipDocument;
+use crate::documents::revocation::RevocationDocument;
+use crate::documents::transaction::TransactionDocument;
+use crate::documents::*;
+use crate::text_document_traits::*;
+
+/// Store a transaction document or just its hash.
+#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
+pub enum TxDocOrTxHash {
+ /// Transaction document
+ TxDoc(Box<TransactionDocument>),
+ /// transaction hash
+ TxHash(Hash),
+}
+
+impl TxDocOrTxHash {
+ /// Lightens the TxDocOrTxHash (for example to store it while minimizing the space required)
+ /// lightening consists in transforming the document by its hash.
+ pub fn reduce(&self) -> TxDocOrTxHash {
+ if let TxDocOrTxHash::TxDoc(ref tx_doc) = self {
+ let tx_doc = tx_doc.deref();
+ if let Some(ref hash) = tx_doc.get_hash_opt() {
+ TxDocOrTxHash::TxHash(*hash)
+ } else {
+ TxDocOrTxHash::TxHash(tx_doc.clone().compute_hash())
+ }
+ } else {
+ self.clone()
+ }
+ }
+ /// Get TxDoc variant
+ pub fn unwrap_doc(&self) -> TransactionDocument {
+ if let TxDocOrTxHash::TxDoc(ref tx_doc) = self {
+ tx_doc.deref().clone()
+ } else {
+ fatal_error!("Try to unwrap_doc() in a TxHash() variant of TxDocOrTxHash !")
+ }
+ }
+}
+
+/// Wrap a Block document.
+///
+/// Must be created by parsing a text document or using a builder.
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
+pub struct BlockDocumentV10 {
+ /// Version
+ pub version: u32,
+ /// Nonce
+ pub nonce: u64,
+ /// number
+ pub number: BlockNumber,
+ /// Minimal proof of work difficulty
+ pub pow_min: usize,
+ /// Local time of the block issuer
+ pub time: u64,
+ /// Average time
+ pub median_time: u64,
+ /// Members count
+ pub members_count: usize,
+ /// Monetary mass
+ pub monetary_mass: usize,
+ /// Unit base (power of ten)
+ pub unit_base: usize,
+ /// Number of compute members in the current frame
+ pub issuers_count: usize,
+ /// Current frame size (in blocks)
+ pub issuers_frame: usize,
+ /// Current frame variation buffer
+ pub issuers_frame_var: isize,
+ /// Currency.
+ pub currency: CurrencyName,
+ /// Document issuer (there should be only one).
+ pub issuers: Vec<PubKey>,
+ /// Document signature (there should be only one).
+ /// This vector is empty, when the block is generated but the proof of work has not yet started
+ pub signatures: Vec<Sig>,
+ /// The hash is None, when the block is generated but the proof of work has not yet started
+ pub hash: Option<BlockHash>,
+ /// Currency parameters (only in genesis block)
+ pub parameters: Option<BlockV10Parameters>,
+ /// Hash of the previous block
+ pub previous_hash: Option<Hash>,
+ /// Issuer of the previous block
+ pub previous_issuer: Option<PubKey>,
+ /// Hash of the deterministic content of the block
+ pub inner_hash: Option<Hash>,
+ /// Amount of new dividend created at this block, None if no dividend is created at this block
+ pub dividend: Option<usize>,
+ /// Identities
+ pub identities: Vec<IdentityDocument>,
+ /// joiners
+ pub joiners: Vec<MembershipDocument>,
+ /// Actives (=renewals)
+ pub actives: Vec<MembershipDocument>,
+ /// Leavers
+ pub leavers: Vec<MembershipDocument>,
+ /// Revokeds
+ pub revoked: Vec<TextDocumentFormat<RevocationDocument>>,
+ /// Excludeds
+ pub excluded: Vec<PubKey>,
+ /// Certifications
+ pub certifications: Vec<TextDocumentFormat<CertificationDocument>>,
+ /// Transactions
+ pub transactions: Vec<TxDocOrTxHash>,
+}
+
+impl BlockDocumentTrait for BlockDocumentV10 {
+ fn common_time(&self) -> u64 {
+ self.median_time
+ }
+ fn compute_hash(&self) -> BlockHash {
+ BlockHash(Hash::compute_str(&self.compute_will_hashed_string()))
+ }
+ fn compute_will_hashed_string(&self) -> String {
+ format!(
+ "{}{}\n",
+ self.compute_will_signed_string(),
+ self.signatures[0]
+ )
+ }
+ fn compute_will_signed_string(&self) -> String {
+ format!(
+ "InnerHash: {}\nNonce: {}\n",
+ self.inner_hash
+ .expect("compute_will_signed_string(): Try to get inner_hash of an uncompleted or reduce block !")
+ .to_hex(),
+ self.nonce
+ )
+ }
+ fn current_frame_size(&self) -> usize {
+ self.issuers_frame
+ }
+ fn generate_compact_inner_text(&self) -> String {
+ let mut identities_str = String::from("");
+ for identity in self.identities.clone() {
+ identities_str.push_str("\n");
+ identities_str.push_str(&identity.generate_compact_text());
+ }
+ let mut joiners_str = String::from("");
+ for joiner in self.joiners.clone() {
+ joiners_str.push_str("\n");
+ joiners_str.push_str(&joiner.generate_compact_text());
+ }
+ let mut actives_str = String::from("");
+ for active in self.actives.clone() {
+ actives_str.push_str("\n");
+ actives_str.push_str(&active.generate_compact_text());
+ }
+ let mut leavers_str = String::from("");
+ for leaver in self.leavers.clone() {
+ leavers_str.push_str("\n");
+ leavers_str.push_str(&leaver.generate_compact_text());
+ }
+ let mut identities_str = String::from("");
+ for identity in self.identities.clone() {
+ identities_str.push_str("\n");
+ identities_str.push_str(&identity.generate_compact_text());
+ }
+ let mut revokeds_str = String::from("");
+ for revocation in self.revoked.clone() {
+ revokeds_str.push_str("\n");
+ revokeds_str.push_str(&revocation.as_compact_text());
+ }
+ let mut excludeds_str = String::from("");
+ for exclusion in self.excluded.clone() {
+ excludeds_str.push_str("\n");
+ excludeds_str.push_str(&exclusion.to_string());
+ }
+ let mut certifications_str = String::from("");
+ for certification in self.certifications.clone() {
+ certifications_str.push_str("\n");
+ certifications_str.push_str(&certification.as_compact_text());
+ }
+ let mut transactions_str = String::from("");
+ for transaction in self.transactions.clone() {
+ if let TxDocOrTxHash::TxDoc(transaction) = transaction {
+ transactions_str.push_str("\n");
+ transactions_str.push_str(&transaction.deref().generate_compact_text());
+ }
+ }
+ let mut dividend_str = String::from("");
+ if let Some(dividend) = self.dividend {
+ if dividend > 0 {
+ dividend_str.push_str("UniversalDividend: ");
+ dividend_str.push_str(÷nd.to_string());
+ dividend_str.push_str("\n");
+ }
+ }
+ let mut parameters_str = String::from("");
+ if let Some(params) = self.parameters {
+ parameters_str.push_str("Parameters: ");
+ parameters_str.push_str(¶ms.to_string());
+ parameters_str.push_str("\n");
+ }
+ let mut previous_hash_str = String::from("");
+ if self.number.0 > 0 {
+ previous_hash_str.push_str("PreviousHash: ");
+ previous_hash_str.push_str(&unwrap!(self.previous_hash).to_string());
+ previous_hash_str.push_str("\n");
+ }
+ let mut previous_issuer_str = String::from("");
+ if self.number.0 > 0 {
+ previous_issuer_str.push_str("PreviousIssuer: ");
+ previous_issuer_str.push_str(
+ &self
+ .previous_issuer
+ .expect("No genesis block must have previous issuer")
+ .to_string(),
+ );
+ previous_issuer_str.push_str("\n");
+ }
+ format!(
+ "Version: {version}
+Type: Block
+Currency: {currency}
+Number: {block_number}
+PoWMin: {pow_min}
+Time: {time}
+MedianTime: {median_time}
+{dividend}UnitBase: {unit_base}
+Issuer: {issuer}
+IssuersFrame: {issuers_frame}
+IssuersFrameVar: {issuers_frame_var}
+DifferentIssuersCount: {issuers_count}
+{parameters}{previous_hash}{previous_issuer}MembersCount: {members_count}
+Identities:{identities}
+Joiners:{joiners}
+Actives:{actives}
+Leavers:{leavers}
+Revoked:{revoked}
+Excluded:{excluded}
+Certifications:{certifications}
+Transactions:{transactions}
+",
+ version = self.version,
+ currency = self.currency,
+ block_number = self.number,
+ pow_min = self.pow_min,
+ time = self.time,
+ median_time = self.median_time,
+ dividend = dividend_str,
+ unit_base = self.unit_base,
+ issuer = self.issuers[0],
+ issuers_frame = self.issuers_frame,
+ issuers_frame_var = self.issuers_frame_var,
+ issuers_count = self.issuers_count,
+ parameters = parameters_str,
+ previous_hash = previous_hash_str,
+ previous_issuer = previous_issuer_str,
+ members_count = self.members_count,
+ identities = identities_str,
+ joiners = joiners_str,
+ actives = actives_str,
+ leavers = leavers_str,
+ revoked = revokeds_str,
+ excluded = excludeds_str,
+ certifications = certifications_str,
+ transactions = transactions_str,
+ )
+ }
+ fn generate_hash(&mut self) {
+ self.hash = Some(self.compute_hash());
+ }
+ fn generate_inner_hash(&mut self) {
+ self.inner_hash = Some(self.compute_inner_hash());
+ }
+ fn hash(&self) -> Option<BlockHash> {
+ self.hash
+ }
+ fn increment_nonce(&mut self) {
+ self.nonce += 1;
+ }
+ fn inner_hash(&self) -> Option<Hash> {
+ self.inner_hash
+ }
+ fn issuers_count(&self) -> usize {
+ self.issuers_count
+ }
+ fn number(&self) -> BlockNumber {
+ self.number
+ }
+ fn previous_blockstamp(&self) -> Blockstamp {
+ if self.number.0 > 0 {
+ Blockstamp {
+ id: BlockNumber(self.number.0 - 1),
+ hash: BlockHash(unwrap!(self.previous_hash)),
+ }
+ } else {
+ Blockstamp::default()
+ }
+ }
+ fn previous_hash(&self) -> Option<Hash> {
+ self.previous_hash
+ }
+ fn reduce(&mut self) {
+ //self.hash = None;
+ self.inner_hash = None;
+ for i in &mut self.identities {
+ i.reduce();
+ }
+ for i in &mut self.joiners {
+ i.reduce();
+ }
+ for i in &mut self.actives {
+ i.reduce();
+ }
+ for i in &mut self.leavers {
+ i.reduce();
+ }
+ for i in &mut self.transactions {
+ i.reduce();
+ }
+ }
+ fn sign(&mut self, privkey: PrivKey) {
+ self.signatures = vec![privkey.sign(self.compute_will_signed_string().as_bytes())];
+ }
+ fn verify_inner_hash(&self) -> bool {
+ match self.inner_hash {
+ Some(inner_hash) => inner_hash == self.compute_inner_hash(),
+ None => false,
+ }
+ }
+ fn verify_hash(&self) -> bool {
+ match self.hash {
+ Some(hash) => {
+ let expected_hash = self.compute_hash();
+ if hash == expected_hash {
+ true
+ } else {
+ warn!(
+ "Block #{} have invalid hash (expected='{}', actual='{}', datas='{}').",
+ self.number.0,
+ expected_hash,
+ hash,
+ self.compute_will_hashed_string()
+ );
+ false
+ }
+ }
+ None => false,
+ }
+ }
+}
+
+impl Document for BlockDocumentV10 {
+ type PublicKey = PubKey;
+
+ #[inline]
+ fn version(&self) -> u16 {
+ 10
+ }
+
+ #[inline]
+ fn currency(&self) -> &str {
+ &self.currency.0
+ }
+
+ #[inline]
+ fn blockstamp(&self) -> Blockstamp {
+ Blockstamp {
+ id: self.number,
+ hash: self
+ .hash
+ .expect("Fatal error : try to get blockstamp of an uncomplete or reduce block !"),
+ }
+ }
+
+ #[inline]
+ fn issuers(&self) -> &Vec<PubKey> {
+ &self.issuers
+ }
+
+ #[inline]
+ fn signatures(&self) -> &Vec<Sig> {
+ &self.signatures
+ }
+
+ #[inline]
+ fn as_bytes(&self) -> &[u8] {
+ fatal_error!("as_bytes() must not be call for BlockDocumentV10 !")
+ }
+
+ #[inline]
+ fn no_as_bytes(&self) -> bool {
+ true
+ }
+
+ #[inline]
+ fn to_bytes(&self) -> Vec<u8> {
+ self.compute_will_signed_string().as_bytes().to_vec()
+ }
+}
+
+impl CompactTextDocument for BlockDocumentV10 {
+ fn as_compact_text(&self) -> String {
+ let compact_inner_text = self.generate_compact_inner_text();
+ format!(
+ "{}InnerHash: {}\nNonce: ",
+ compact_inner_text,
+ self.inner_hash
+ .expect(
+ "as_compact_text(): Try to get inner_hash of an uncompleted or reduce block !"
+ )
+ .to_hex()
+ )
+ }
+}
+
+impl TextDocument for BlockDocumentV10 {
+ type CompactTextDocument_ = BlockDocumentV10;
+
+ fn as_text(&self) -> &str {
+ fatal_error!(
+ "Dev error: function not implemented. Please use to_compact_document() instead"
+ );
+ }
+
+ fn to_compact_document(&self) -> Self::CompactTextDocument_ {
+ self.clone()
+ }
+}
+
+impl IntoSpecializedDocument<DUBPDocument> for BlockDocumentV10 {
+ fn into_specialized(self) -> DUBPDocument {
+ DUBPDocument::Block(Box::new(self))
+ }
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct BlockDocumentV10Stringified {
+ /// Version
+ pub version: u64,
+ /// Nonce
+ pub nonce: u64,
+ /// number
+ pub number: u64,
+ /// Minimal proof of work difficulty
+ pub pow_min: u64,
+ /// Local time of the block issuer
+ pub time: u64,
+ /// Average time
+ pub median_time: u64,
+ /// Members count
+ pub members_count: u64,
+ /// Monetary mass
+ pub monetary_mass: u64,
+ /// Unit base (power of ten)
+ pub unit_base: u64,
+ /// Number of compute members in the current frame
+ pub issuers_count: u64,
+ /// Current frame size (in blocks)
+ pub issuers_frame: i64,
+ /// Current frame variation buffer
+ pub issuers_frame_var: i64,
+ /// Currency.
+ pub currency: String,
+ /// Document issuer (there should be only one).
+ pub issuers: Vec<String>,
+ /// Document signature (there should be only one).
+ /// This vector is empty, when the block is generated but the proof of work has not yet started
+ pub signatures: Vec<String>,
+ /// The hash is None, when the block is generated but the proof of work has not yet started
+ pub hash: Option<String>,
+ /// Currency parameters (only in genesis block)
+ pub parameters: Option<String>,
+ /// Hash of the previous block
+ pub previous_hash: Option<String>,
+ /// Issuer of the previous block
+ pub previous_issuer: Option<String>,
+ /// Hash of the deterministic content of the block
+ pub inner_hash: Option<String>,
+ /// Amount of new dividend created at this block, None if no dividend is created at this block
+ pub dividend: Option<u64>,
+ /// Identities
+ pub identities: Vec<IdentityStringDocument>,
+ /// joiners
+ pub joiners: Vec<MembershipStringDocument>,
+ /// Actives (=renewals)
+ pub actives: Vec<MembershipStringDocument>,
+ /// Leavers
+ pub leavers: Vec<MembershipStringDocument>,
+ /// Revokeds
+ pub revoked: Vec<CompactRevocationStringDocument>,
+ /// Excludeds
+ pub excluded: Vec<String>,
+ /// Certifications
+ pub certifications: Vec<CompactCertificationStringDocument>,
+ /// Transactions
+ pub transactions: Vec<TransactionDocumentStringified>,
+}
+
+impl ToStringObject for BlockDocumentV10 {
+ type StringObject = BlockDocumentV10Stringified;
+ /// Transforms an object into a json object
+ fn to_string_object(&self) -> BlockDocumentV10Stringified {
+ BlockDocumentV10Stringified {
+ version: u64::from(self.version),
+ nonce: self.nonce,
+ number: u64::from(self.number.0),
+ pow_min: self.pow_min as u64,
+ time: self.time,
+ median_time: self.median_time,
+ members_count: self.members_count as u64,
+ monetary_mass: self.monetary_mass as u64,
+ unit_base: self.unit_base as u64,
+ issuers_count: self.issuers_count as u64,
+ issuers_frame: self.issuers_frame as i64,
+ issuers_frame_var: self.issuers_frame_var as i64,
+ currency: self.currency.to_string(),
+ issuers: self.issuers.iter().map(ToString::to_string).collect(),
+ signatures: self.signatures.iter().map(ToString::to_string).collect(),
+ hash: self.hash.map(|hash| hash.to_string()),
+ parameters: self.parameters.map(|parameters| parameters.to_string()),
+ previous_hash: self.previous_hash.map(|hash| hash.to_string()),
+ previous_issuer: self.previous_issuer.map(|p| p.to_string()),
+ inner_hash: self.inner_hash.map(|hash| hash.to_string()),
+ dividend: self.dividend.map(|dividend| dividend as u64),
+ identities: self
+ .identities
+ .iter()
+ .map(ToStringObject::to_string_object)
+ .collect(),
+ joiners: self
+ .joiners
+ .iter()
+ .map(ToStringObject::to_string_object)
+ .collect(),
+ actives: self
+ .actives
+ .iter()
+ .map(ToStringObject::to_string_object)
+ .collect(),
+ leavers: self
+ .leavers
+ .iter()
+ .map(ToStringObject::to_string_object)
+ .collect(),
+ revoked: self
+ .revoked
+ .iter()
+ .map(|revocation_doc| match revocation_doc {
+ TextDocumentFormat::Complete(complete_revoc_doc) => {
+ complete_revoc_doc.to_compact_document().to_string_object()
+ }
+ TextDocumentFormat::Compact(compact_revoc_doc) => {
+ compact_revoc_doc.to_string_object()
+ }
+ })
+ .collect(),
+ excluded: self.excluded.iter().map(ToString::to_string).collect(),
+ certifications: self
+ .certifications
+ .iter()
+ .map(|cert_doc| match cert_doc {
+ TextDocumentFormat::Complete(complete_cert_doc) => {
+ complete_cert_doc.to_compact_document().to_string_object()
+ }
+ TextDocumentFormat::Compact(compact_cert_doc) => {
+ compact_cert_doc.to_string_object()
+ }
+ })
+ .collect(),
+ transactions: self
+ .transactions
+ .iter()
+ .map(|tx_doc_or_tx_hash| match tx_doc_or_tx_hash {
+ TxDocOrTxHash::TxDoc(tx_doc) => tx_doc.to_string_object(),
+ TxDocOrTxHash::TxHash(_) => {
+ fatal_error!("Try to stringify block without their tx documents")
+ }
+ })
+ .collect(),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::certification::CertificationDocumentParser;
+ use super::transaction::TransactionDocumentParser;
+ use super::*;
+ use crate::{Document, VerificationResult};
+
+ #[test]
+ fn generate_and_verify_empty_block() {
+ let mut block = BlockDocumentV10 {
+ nonce: 100_010_200_000_006_940,
+ version: 10,
+ number: BlockNumber(174_260),
+ pow_min: 68,
+ time: 1_525_296_873,
+ median_time: 1_525_292_577,
+ members_count: 33,
+ monetary_mass: 15_633_687,
+ unit_base: 0,
+ issuers_count: 8,
+ issuers_frame: 41,
+ issuers_frame_var: 0,
+ currency: CurrencyName(String::from("g1-test")),
+ issuers: vec![PubKey::Ed25519(ed25519::PublicKey::from_base58("39Fnossy1GrndwCnAXGDw3K5UYXhNXAFQe7yhYZp8ELP").unwrap())],
+ signatures: vec![Sig::Ed25519(ed25519::Signature::from_base64("lqXrNOopjM39oM7hgB7Vq13uIohdCuLlhh/q8RVVEZ5UVASphow/GXikCdhbWID19Bn0XrXzTbt/R7akbE9xAg==").unwrap())],
+ hash: None,
+ parameters: None,
+ previous_hash: Some(Hash::from_hex("0000A7D4361B9EBF4CE974A521149A73E8A5DE9B73907AB3BC918726AED7D40A").expect("fail to parse previous_hash")),
+ previous_issuer: Some(PubKey::Ed25519(ed25519::PublicKey::from_base58("EPKuZA1Ek5y8S1AjAmAPtGrVCMFqUGzUEAa7Ei62CY2L").unwrap())),
+ inner_hash: None,
+ dividend: None,
+ identities: Vec::new(),
+ joiners: Vec::new(),
+ actives: Vec::new(),
+ leavers: Vec::new(),
+ revoked: Vec::new(),
+ excluded: Vec::new(),
+ certifications: Vec::new(),
+ transactions: Vec::new(),
+ };
+ // test inner_hash computation
+ block.generate_inner_hash();
+ println!("{}", block.generate_compact_text());
+ assert_eq!(
+ block
+ .inner_hash
+ .expect("tests::generate_and_verify_empty_block: Try to get inner_hash of an uncompleted or reduce block !")
+ .to_hex(),
+ "58E4865A47A46E0DF1449AABC449B5406A12047C413D61B5E17F86BE6641E7B0"
+ );
+ // Test signature validity
+ assert_eq!(block.verify_signatures(), VerificationResult::Valid());
+ // Test hash computation
+ block.generate_hash();
+ assert_eq!(
+ block
+ .hash
+ .expect("Try to get hash of an uncompleted or reduce block !")
+ .0
+ .to_hex(),
+ "00002EE584F36C15D3EB21AAC78E0896C75EF9070E73B4EC33BFA2C3D561EEB2"
+ );
+ }
+
+ #[test]
+ fn generate_and_verify_block() {
+ let cert1 = CertificationDocumentParser::parse("Version: 10
+Type: Certification
+Currency: g1
+Issuer: 6TAzLWuNcSqgNDNpAutrKpPXcGJwy1ZEMeVvZSZNs2e3
+IdtyIssuer: CYPsYTdt87Tx6cCiZs9KD4jqPgYxbcVEqVZpRgJ9jjoV
+IdtyUniqueID: PascaleM
+IdtyTimestamp: 97401-0000003821911909F98519CC773D2D3E5CFE3D5DBB39F4F4FF33B96B4D41800E
+IdtySignature: QncUVXxZ2NfARjdJOn6luILvDuG1NuK9qSoaU4CST2Ij8z7oeVtEgryHl+EXOjSe6XniALsCT0gU8wtadcA/Cw==
+CertTimestamp: 106669-000003682E6FE38C44433DCE92E8B2A26C69B6D7867A2BAED231E788DDEF4251
+UmseG2XKNwKcY8RFi6gUCT91udGnnNmSh7se10J1jeRVlwf+O2Tyb2Cccot9Dt7BO4+Kx2P6vFJB3oVGGHMxBA==").expect("Fail to parse cert1");
+
+ let tx1 = TransactionDocumentParser::parse("Version: 10
+Type: Transaction
+Currency: g1
+Blockstamp: 107982-000001242F6DA51C06A915A96C58BAA37AB3D1EB51F6E1C630C707845ACF764B
+Locktime: 0
+Issuers:
+8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3
+Inputs:
+1002:0:D:8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3:106345
+Unlocks:
+0:SIG(0)
+Outputs:
+1002:0:SIG(CitdnuQgZ45tNFCagay7Wh12gwwHM8VLej1sWmfHWnQX)
+Comment: DU symbolique pour demander le codage de nouvelles fonctionnalites cf. https://forum.monnaie-libre.fr/t/creer-de-nouvelles-fonctionnalites-dans-cesium-les-autres-applications/2025 Merci
+T0LlCcbIn7xDFws48H8LboN6NxxwNXXTovG4PROLf7tkUAueHFWjfwZFKQXeZEHxfaL1eYs3QspGtLWUHPRVCQ==").expect("Fail to parse tx1");
+
+ let tx2 = TransactionDocumentParser::parse("Version: 10
+Type: Transaction
+Currency: g1
+Blockstamp: 107982-000001242F6DA51C06A915A96C58BAA37AB3D1EB51F6E1C630C707845ACF764B
+Locktime: 0
+Issuers:
+8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3
+Inputs:
+1002:0:D:8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3:106614
+Unlocks:
+0:SIG(0)
+Outputs:
+1002:0:SIG(78ZwwgpgdH5uLZLbThUQH7LKwPgjMunYfLiCfUCySkM8)
+Comment: DU symbolique pour demander le codage de nouvelles fonctionnalites cf. https://forum.monnaie-libre.fr/t/creer-de-nouvelles-fonctionnalites-dans-cesium-les-autres-applications/2025 Merci
+a9PHPuSfw7jW8FRQHXFsGi/bnLjbtDnTYvEVgUC9u0WlR7GVofa+Xb+l5iy6NwuEXiwvueAkf08wPVY8xrNcCg==").expect("Fail to parse tx2");
+
+ let mut block = BlockDocumentV10 {
+ nonce: 10_300_000_018_323,
+ version: 10,
+ number: BlockNumber(107_984),
+ pow_min: 88,
+ time: 1_522_685_861,
+ median_time: 1522683184,
+ members_count: 896,
+ monetary_mass: 140_469_765,
+ unit_base: 0,
+ issuers_count: 42,
+ issuers_frame: 211,
+ issuers_frame_var: 0,
+ currency: CurrencyName(String::from("g1")),
+ issuers: vec![PubKey::Ed25519(ed25519::PublicKey::from_base58("DA4PYtXdvQqk1nCaprXH52iMsK5Ahxs1nRWbWKLhpVkQ").unwrap())],
+ signatures: vec![Sig::Ed25519(ed25519::Signature::from_base64("92id58VmkhgVNee4LDqBGSm8u/ooHzAD67JM6fhAE/CV8LCz7XrMF1DvRl+eRpmlaVkp6I+Iy8gmZ1WUM5C8BA==").unwrap())],
+ hash: None,
+ parameters: None,
+ previous_hash: Some(Hash::from_hex("000001144968D0C3516BE6225E4662F182E28956AF46DD7FB228E3D0F9413FEB").expect("fail to parse previous_hash")),
+ previous_issuer: Some(PubKey::Ed25519(ed25519::PublicKey::from_base58("D3krfq6J9AmfpKnS3gQVYoy7NzGCc61vokteTS8LJ4YH").unwrap())),
+ inner_hash: None,
+ dividend: None,
+ identities: Vec::new(),
+ joiners: Vec::new(),
+ actives: Vec::new(),
+ leavers: Vec::new(),
+ revoked: Vec::new(),
+ excluded: Vec::new(),
+ certifications: vec![TextDocumentFormat::Complete(cert1)],
+ transactions: vec![TxDocOrTxHash::TxDoc(Box::new(tx1)), TxDocOrTxHash::TxDoc(Box::new(tx2))],
+ };
+ // test inner_hash computation
+ block.generate_inner_hash();
+ println!("{}", block.generate_compact_text());
+ assert_eq!(
+ block
+ .inner_hash
+ .expect("tests::generate_and_verify_block: Try to get inner_hash of an uncompleted or reduce block !")
+ .to_hex(),
+ "C8AB69E33ECE2612EADC7AB30D069B1F1A3D8C95EBBFD50DE583AC8E3666CCA1"
+ );
+ // test generate_compact_text()
+ assert_eq!(
+ block.generate_compact_text(),
+ "Version: 10
+Type: Block
+Currency: g1
+Number: 107984
+PoWMin: 88
+Time: 1522685861
+MedianTime: 1522683184
+UnitBase: 0
+Issuer: DA4PYtXdvQqk1nCaprXH52iMsK5Ahxs1nRWbWKLhpVkQ
+IssuersFrame: 211
+IssuersFrameVar: 0
+DifferentIssuersCount: 42
+PreviousHash: 000001144968D0C3516BE6225E4662F182E28956AF46DD7FB228E3D0F9413FEB
+PreviousIssuer: D3krfq6J9AmfpKnS3gQVYoy7NzGCc61vokteTS8LJ4YH
+MembersCount: 896
+Identities:
+Joiners:
+Actives:
+Leavers:
+Revoked:
+Excluded:
+Certifications:
+6TAzLWuNcSqgNDNpAutrKpPXcGJwy1ZEMeVvZSZNs2e3:CYPsYTdt87Tx6cCiZs9KD4jqPgYxbcVEqVZpRgJ9jjoV:106669:UmseG2XKNwKcY8RFi6gUCT91udGnnNmSh7se10J1jeRVlwf+O2Tyb2Cccot9Dt7BO4+Kx2P6vFJB3oVGGHMxBA==
+Transactions:
+TX:10:1:1:1:1:1:0
+107982-000001242F6DA51C06A915A96C58BAA37AB3D1EB51F6E1C630C707845ACF764B
+8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3
+1002:0:D:8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3:106345
+0:SIG(0)
+1002:0:SIG(CitdnuQgZ45tNFCagay7Wh12gwwHM8VLej1sWmfHWnQX)
+DU symbolique pour demander le codage de nouvelles fonctionnalites cf. https://forum.monnaie-libre.fr/t/creer-de-nouvelles-fonctionnalites-dans-cesium-les-autres-applications/2025 Merci
+T0LlCcbIn7xDFws48H8LboN6NxxwNXXTovG4PROLf7tkUAueHFWjfwZFKQXeZEHxfaL1eYs3QspGtLWUHPRVCQ==
+TX:10:1:1:1:1:1:0
+107982-000001242F6DA51C06A915A96C58BAA37AB3D1EB51F6E1C630C707845ACF764B
+8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3
+1002:0:D:8dkCwvAqSczUjKsoVMDPVbQ3i6bBQeBQYawL87kqTSQ3:106614
+0:SIG(0)
+1002:0:SIG(78ZwwgpgdH5uLZLbThUQH7LKwPgjMunYfLiCfUCySkM8)
+DU symbolique pour demander le codage de nouvelles fonctionnalites cf. https://forum.monnaie-libre.fr/t/creer-de-nouvelles-fonctionnalites-dans-cesium-les-autres-applications/2025 Merci
+a9PHPuSfw7jW8FRQHXFsGi/bnLjbtDnTYvEVgUC9u0WlR7GVofa+Xb+l5iy6NwuEXiwvueAkf08wPVY8xrNcCg==
+InnerHash: C8AB69E33ECE2612EADC7AB30D069B1F1A3D8C95EBBFD50DE583AC8E3666CCA1
+Nonce: "
+ );
+ // Test signature validity
+ assert_eq!(block.verify_signatures(), VerificationResult::Valid());
+ // Test hash computation
+ block.generate_hash();
+ assert_eq!(
+ block
+ .hash
+ .expect("Try to get hash of an uncompleted or reduce block !")
+ .0
+ .to_hex(),
+ "000004F8B84A3590243BA562E5F2BA379F55A0B387C5D6FAC1022DFF7FFE6014"
+ );
+ }
+
+ #[test]
+ fn generate_and_verify_block_2() {
+ let ms1 = MembershipDocumentParser::parse(
+ "Version: 10
+Type: Membership
+Currency: g1
+Issuer: 4VZkro3N7VonygybESHngKUABA6gSrbW77Ktb94zE969
+Block: 165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2
+Membership: IN
+UserID: piaaf31
+CertTS: 74077-0000022816648B2F7801E059F67CCD0C023FF0ED84459D52C70494D74DDCC6F6
+gvaZ1QnJf8FjjRDJ0cYusgpBgQ8r0NqEz39BooH6DtIrgX+WTeXuLSnjZDl35VCBjokvyjry+v0OkTT8FKpABA==",
+ )
+ .expect("Fail to parse ms1");
+
+ let tx1 = TransactionDocumentParser::parse(
+ "Version: 10
+Type: Transaction
+Currency: g1
+Blockstamp: 165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2
+Locktime: 0
+Issuers:
+51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2
+Inputs:
+1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:163766
+1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164040
+1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164320
+1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164584
+1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164849
+1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:165118
+1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:165389
+Unlocks:
+0:SIG(0)
+1:SIG(0)
+2:SIG(0)
+3:SIG(0)
+4:SIG(0)
+5:SIG(0)
+6:SIG(0)
+Outputs:
+7000:0:SIG(98wxzS683Tc1WWm1YxpL5WpxS7wBa1mZBccKSsYpaant)
+28:0:SIG(51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2)
+Comment: Panier mixte plus 40 pommes merci
+7o/yIh0BNSAv5pNmHz04uUBl8TuP2s4HRFMtKeGFQfXNYJPUyJTP/dj6hdrgKtJkm5dCfbxT4KRy6wJf+dj1Cw==",
+ )
+ .expect("Fail to parse tx1");
+
+ let tx2 = TransactionDocumentParser::parse(
+ "Version: 10
+Type: Transaction
+Currency: g1
+Blockstamp: 165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2
+Locktime: 0
+Issuers:
+3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX
+Inputs:
+1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:148827
+1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149100
+1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149370
+1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149664
+1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149943
+1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:150222
+Unlocks:
+0:SIG(0)
+1:SIG(0)
+2:SIG(0)
+3:SIG(0)
+4:SIG(0)
+5:SIG(0)
+Outputs:
+6000:0:SIG(AopwTfXhj8VqZReFJYGGWnoWnXNj3RgaqFcGGywXpZrD)
+12:0:SIG(3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX)
+Comment: En reglement de tes bons bocaux de fruits et legumes
+nxr4exGrt16jteN9ZX3XZPP9l+X0OUbZ1o/QjE1hbWQNtVU3HhH9SJoEvNj2iVl3gCRr9u2OA9uj9vCyUDyjAg==
+",
+ )
+ .expect("Fail to parse tx2");
+
+ let mut block = BlockDocumentV10 {
+ nonce: 10_300_000_090_296,
+ version: 10,
+ number: BlockNumber(165_647),
+ pow_min: 90,
+ time: 1_540_633_175,
+ median_time: 1_540_627_811,
+ members_count: 1402,
+ monetary_mass: 386_008_811,
+ unit_base: 0,
+ issuers_count: 37,
+ issuers_frame: 186,
+ issuers_frame_var: 0,
+ currency: CurrencyName(String::from("g1")),
+ issuers: vec![PubKey::Ed25519(ed25519::PublicKey::from_base58("A4pc9Uuk4NXkWG8CibicjjPpEPdiup1mhjMoRWUZsonq").unwrap())],
+ signatures: vec![Sig::Ed25519(ed25519::Signature::from_base64("2Z/+9ADdZvHXs19YR8+qDzgfl8WJlBG5PcbFvBG9TOuUJbjAdxhcgxrFrSRIABGWcCrIgLkB805fZVLP8jOjBA==").unwrap())],
+ hash: None,
+ parameters: None,
+ previous_hash: Some(Hash::from_hex("000003E78FA4133F2C13B416F330C8DFB5A41EB87E37190615DB334F2C914A51").expect("fail to parse previous_hash")),
+ previous_issuer: Some(PubKey::Ed25519(ed25519::PublicKey::from_base58("8NmGZmGjL1LUgJQRg282yQF7KTdQuRNAg8QfSa2qvd65").unwrap())),
+ inner_hash: None,//Some(Hash::from_hex("3B49ECC1475549CFD94CA7B399311548A0FD0EC93C8EDD5670DAA5A958A41846").expect("fail to parse inner_hash")),
+ dividend: None,
+ identities: vec![],
+ joiners: vec![],
+ actives: vec![ms1],
+ leavers: vec![],
+ revoked: vec![],
+ excluded: vec![],
+ certifications: vec![],
+ transactions: vec![TxDocOrTxHash::TxDoc(Box::new(tx1)), TxDocOrTxHash::TxDoc(Box::new(tx2))],
+ };
+ // test inner_hash computation
+ block.generate_inner_hash();
+ println!("{}", block.generate_compact_text());
+ assert_eq!(
+ block
+ .inner_hash
+ .expect("tests::generate_and_verify_block_2: Try to get inner_hash of an uncompleted or reduce block !")
+ .to_hex(),
+ "3B49ECC1475549CFD94CA7B399311548A0FD0EC93C8EDD5670DAA5A958A41846"
+ );
+ // test generate_compact_text()
+ let block_compact_text = block.generate_compact_text();
+ assert_eq!(
+ block_compact_text,
+ "Version: 10\nType: Block\nCurrency: g1\nNumber: 165647\nPoWMin: 90\nTime: 1540633175\nMedianTime: 1540627811\nUnitBase: 0\nIssuer: A4pc9Uuk4NXkWG8CibicjjPpEPdiup1mhjMoRWUZsonq\nIssuersFrame: 186\nIssuersFrameVar: 0\nDifferentIssuersCount: 37\nPreviousHash: 000003E78FA4133F2C13B416F330C8DFB5A41EB87E37190615DB334F2C914A51\nPreviousIssuer: 8NmGZmGjL1LUgJQRg282yQF7KTdQuRNAg8QfSa2qvd65\nMembersCount: 1402\nIdentities:\nJoiners:\nActives:\n4VZkro3N7VonygybESHngKUABA6gSrbW77Ktb94zE969:gvaZ1QnJf8FjjRDJ0cYusgpBgQ8r0NqEz39BooH6DtIrgX+WTeXuLSnjZDl35VCBjokvyjry+v0OkTT8FKpABA==:165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2:74077-0000022816648B2F7801E059F67CCD0C023FF0ED84459D52C70494D74DDCC6F6:piaaf31\nLeavers:\nRevoked:\nExcluded:\nCertifications:\nTransactions:\nTX:10:1:7:7:2:1:0\n165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2\n51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:163766\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164040\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164320\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164584\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:164849\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:165118\n1004:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:165389\n0:SIG(0)\n1:SIG(0)\n2:SIG(0)\n3:SIG(0)\n4:SIG(0)\n5:SIG(0)\n6:SIG(0)\n7000:0:SIG(98wxzS683Tc1WWm1YxpL5WpxS7wBa1mZBccKSsYpaant)\n28:0:SIG(51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2)\nPanier mixte plus 40 pommes merci\n7o/yIh0BNSAv5pNmHz04uUBl8TuP2s4HRFMtKeGFQfXNYJPUyJTP/dj6hdrgKtJkm5dCfbxT4KRy6wJf+dj1Cw==\nTX:10:1:6:6:2:1:0\n165645-000002D30130881939961A38D51CA233B3C696AA604439036DB1AAA4ED5046D2\n3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:148827\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149100\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149370\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149664\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:149943\n1002:0:D:3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX:150222\n0:SIG(0)\n1:SIG(0)\n2:SIG(0)\n3:SIG(0)\n4:SIG(0)\n5:SIG(0)\n6000:0:SIG(AopwTfXhj8VqZReFJYGGWnoWnXNj3RgaqFcGGywXpZrD)\n12:0:SIG(3Uwq4qNp2A97P1XQueEBCxmnvgtAKMdfrEq6VB7Ph2qX)\nEn reglement de tes bons bocaux de fruits et legumes\nnxr4exGrt16jteN9ZX3XZPP9l+X0OUbZ1o/QjE1hbWQNtVU3HhH9SJoEvNj2iVl3gCRr9u2OA9uj9vCyUDyjAg==\nInnerHash: 3B49ECC1475549CFD94CA7B399311548A0FD0EC93C8EDD5670DAA5A958A41846\nNonce: "
+ );
+ // Test signature validity
+ assert_eq!(block.verify_signatures(), VerificationResult::Valid());
+ // Test hash computation
+ block.generate_hash();
+ assert_eq!(
+ block
+ .hash
+ .expect("Try to get hash of an uncompleted or reduce block !")
+ .0
+ .to_hex(),
+ "000002026E32A3D649B34968AAF9D03C4F19A5954229C54A801BBB1CD216B230"
+ );
+ }
+}
diff --git a/lib/tools/documents/src/documents/certification.rs b/lib/tools/documents/src/documents/certification.rs
index b853ade4..9726e78e 100644
--- a/lib/tools/documents/src/documents/certification.rs
+++ b/lib/tools/documents/src/documents/certification.rs
@@ -159,7 +159,6 @@ impl CertificationDocument {
impl Document for CertificationDocument {
type PublicKey = PubKey;
- type CurrencyType = str;
fn version(&self) -> u16 {
10
diff --git a/lib/tools/documents/src/documents/identity.rs b/lib/tools/documents/src/documents/identity.rs
index 15cb0135..f91bed48 100644
--- a/lib/tools/documents/src/documents/identity.rs
+++ b/lib/tools/documents/src/documents/identity.rs
@@ -88,7 +88,6 @@ impl IdentityDocument {
impl Document for IdentityDocument {
type PublicKey = PubKey;
- type CurrencyType = str;
fn version(&self) -> u16 {
10
diff --git a/lib/tools/documents/src/documents/membership.rs b/lib/tools/documents/src/documents/membership.rs
index 528772f5..90810d8e 100644
--- a/lib/tools/documents/src/documents/membership.rs
+++ b/lib/tools/documents/src/documents/membership.rs
@@ -141,7 +141,6 @@ impl MembershipDocument {
impl Document for MembershipDocument {
type PublicKey = PubKey;
- type CurrencyType = str;
fn version(&self) -> u16 {
10
diff --git a/lib/tools/documents/src/documents/mod.rs b/lib/tools/documents/src/documents/mod.rs
index c2535657..db92485f 100644
--- a/lib/tools/documents/src/documents/mod.rs
+++ b/lib/tools/documents/src/documents/mod.rs
@@ -39,7 +39,7 @@ pub mod transaction;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DUBPDocument {
/// Block document.
- Block(Box<BlockDocument>),
+ Block(Box<BlockDocumentV10>),
/// Transaction document.
Transaction(Box<TransactionDocument>),
@@ -61,7 +61,7 @@ pub enum DUBPDocument {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DUBPDocumentStr {
/// Block document (not yet implemented)
- Block(Box<BlockDocumentStringified>),
+ Block(Box<BlockDocumentV10Stringified>),
/// Transaction document.
Transaction(Box<TransactionDocumentStringified>),
@@ -172,7 +172,6 @@ mod tests {
impl Document for PlainTextDocument {
type PublicKey = PubKey;
- type CurrencyType = str;
fn version(&self) -> u16 {
unimplemented!()
diff --git a/lib/tools/documents/src/documents/revocation.rs b/lib/tools/documents/src/documents/revocation.rs
index 37ee248f..9d64bbb8 100644
--- a/lib/tools/documents/src/documents/revocation.rs
+++ b/lib/tools/documents/src/documents/revocation.rs
@@ -127,7 +127,6 @@ impl RevocationDocument {
impl Document for RevocationDocument {
type PublicKey = PubKey;
- type CurrencyType = str;
fn version(&self) -> u16 {
10
diff --git a/lib/tools/documents/src/documents/transaction.rs b/lib/tools/documents/src/documents/transaction.rs
index 3f237bed..c293fa75 100644
--- a/lib/tools/documents/src/documents/transaction.rs
+++ b/lib/tools/documents/src/documents/transaction.rs
@@ -648,7 +648,6 @@ impl TransactionDocument {
impl Document for TransactionDocument {
type PublicKey = PubKey;
- type CurrencyType = str;
fn version(&self) -> u16 {
10
diff --git a/lib/tools/documents/src/lib.rs b/lib/tools/documents/src/lib.rs
index 282c50f6..e0778c89 100644
--- a/lib/tools/documents/src/lib.rs
+++ b/lib/tools/documents/src/lib.rs
@@ -152,26 +152,46 @@ impl Debug for BlockHash {
pub trait Document: Debug + Clone + PartialEq + Eq {
/// Type of the `PublicKey` used by the document.
type PublicKey: PublicKey;
- /// Data type of the currency code used by the document.
- type CurrencyType: ?Sized;
- /// Get document version.
- fn version(&self) -> u16;
-
- /// Get document currency.
- fn currency(&self) -> &Self::CurrencyType;
+ /// Get document as bytes for signature verification.
+ fn as_bytes(&self) -> &[u8];
/// Get document blockstamp
fn blockstamp(&self) -> Blockstamp;
+ /// Get document currency name.
+ fn currency(&self) -> &str;
+
/// Iterate over document issuers.
fn issuers(&self) -> &Vec<Self::PublicKey>;
+ /// Some documents do not directly store the sequence of bytes that will be signed but generate
+ // it on request, so these types of documents cannot provide a reference to the signed bytes.
+ fn no_as_bytes(&self) -> bool {
+ false
+ }
+
+ /// Get document to bytes for signature verification.
+ fn to_bytes(&self) -> Vec<u8> {
+ self.as_bytes().to_vec()
+ }
+
/// Iterate over document signatures.
fn signatures(&self) -> &Vec<<Self::PublicKey as PublicKey>::Signature>;
- /// Get document as bytes for signature verification.
- fn as_bytes(&self) -> &[u8];
+ /// Verify one signature
+ #[inline]
+ fn verify_one_signature(
+ &self,
+ public_key: &Self::PublicKey,
+ signature: &<Self::PublicKey as PublicKey>::Signature,
+ ) -> bool {
+ if self.no_as_bytes() {
+ public_key.verify(&self.to_bytes(), signature)
+ } else {
+ public_key.verify(self.as_bytes(), signature)
+ }
+ }
/// Verify signatures of document content (as text format)
fn verify_signatures(&self) -> VerificationResult {
@@ -183,11 +203,12 @@ pub trait Document: Debug + Clone + PartialEq + Eq {
} else {
let issuers = self.issuers();
let signatures = self.signatures();
+
let mismatches: Vec<_> = issuers
.iter()
.zip(signatures)
.enumerate()
- .filter(|&(_, (key, signature))| !key.verify(self.as_bytes(), signature))
+ .filter(|&(_, (key, signature))| !self.verify_one_signature(key, signature))
.map(|(i, _)| i)
.collect();
@@ -198,6 +219,9 @@ pub trait Document: Debug + Clone + PartialEq + Eq {
}
}
}
+
+ /// Get document version.
+ fn version(&self) -> u16;
}
/// List of possible results for signature verification.
diff --git a/lib/tools/documents/src/parsers/blocks.rs b/lib/tools/documents/src/parsers/blocks.rs
index 6f5b75ee..8c74f377 100644
--- a/lib/tools/documents/src/parsers/blocks.rs
+++ b/lib/tools/documents/src/parsers/blocks.rs
@@ -13,7 +13,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
-use crate::documents::block::{BlockDocument, TxDocOrTxHash};
+use crate::documents::block::{v10::TxDocOrTxHash, BlockDocument, BlockDocumentV10};
use crate::documents::membership::MembershipType;
use crate::parsers::{serde_json_value_to_pest_json_value, DefaultHasher};
use crate::*;
@@ -46,7 +46,7 @@ pub fn parse_json_block(json_block: &JSONValue<DefaultHasher>) -> Result<BlockDo
let block_number = get_number(json_block, "number")?.trunc() as u32;
- Ok(BlockDocument {
+ Ok(BlockDocument::V10(BlockDocumentV10 {
version: get_number(json_block, "version")?.trunc() as u32,
nonce: get_u64(json_block, "nonce")?,
number: BlockNumber(block_number),
@@ -59,7 +59,7 @@ pub fn parse_json_block(json_block: &JSONValue<DefaultHasher>) -> Result<BlockDo
.trunc() as usize,
unit_base: get_number(json_block, "unitbase")?.trunc() as usize,
issuers_count: get_number(json_block, "issuersCount")?.trunc() as usize,
- issuers_frame: get_number(json_block, "issuersFrame")?.trunc() as isize,
+ issuers_frame: get_number(json_block, "issuersFrame")?.trunc() as usize,
issuers_frame_var: get_number(json_block, "issuersFrameVar")?.trunc() as isize,
currency: CurrencyName(currency.to_owned()),
issuers: vec![PubKey::Ed25519(ed25519::PublicKey::from_base58(get_str(
@@ -134,13 +134,13 @@ pub fn parse_json_block(json_block: &JSONValue<DefaultHasher>) -> Result<BlockDo
.map(|tx| crate::parsers::transactions::parse_json_transaction(tx))
.map(|tx_result| tx_result.map(|tx_doc| TxDocOrTxHash::TxDoc(Box::new(tx_doc))))
.collect::<Result<Vec<TxDocOrTxHash>, Error>>()?,
- inner_hash_and_nonce_str: "".to_owned(),
- })
+ }))
}
#[cfg(test)]
mod tests {
use super::*;
+ use crate::documents::block::BlockDocumentTrait;
#[test]
fn parse_empty_json_block() {
@@ -180,7 +180,7 @@ mod tests {
let block_json_value = json_pest_parser::parse_json_string(block_json_str)
.expect("Fail to parse json block !");
assert_eq!(
- BlockDocument {
+ BlockDocument::V10(BlockDocumentV10 {
version: 10,
nonce: 10200000037108,
number: BlockNumber(7),
@@ -231,8 +231,7 @@ mod tests {
excluded: vec![],
certifications: vec![],
transactions: vec![],
- inner_hash_and_nonce_str: "".to_owned(),
- },
+ }),
parse_json_block(&block_json_value).expect("Fail to parse block_json_value !")
);
}
@@ -302,7 +301,7 @@ mod tests {
let block_json_value = json_pest_parser::parse_json_string(block_json_str)
.expect("Fail to parse json block !");
- let expected_block = BlockDocument {
+ let expected_block = BlockDocument::V10(BlockDocumentV10 {
version: 10,
nonce: 10100000033688,
number: BlockNumber(52),
@@ -353,8 +352,7 @@ mod tests {
excluded: vec![],
certifications: vec![],
transactions: vec![TxDocOrTxHash::TxDoc(Box::new(crate::parsers::tests::first_g1_tx_doc()))],
- inner_hash_and_nonce_str: "".to_owned(),
- };
+ });
assert_eq!(
expected_block,
parse_json_block(&block_json_value).expect("Fail to parse block_json_value !")
diff --git a/lib/tools/documents/src/text_document_traits.rs b/lib/tools/documents/src/text_document_traits.rs
index 0c4ce914..806ff22a 100644
--- a/lib/tools/documents/src/text_document_traits.rs
+++ b/lib/tools/documents/src/text_document_traits.rs
@@ -57,7 +57,7 @@ impl<D: TextDocument> CompactTextDocument for TextDocumentFormat<D> {
}
/// Trait for a V10 document.
-pub trait TextDocument: Document<PublicKey = PubKey, CurrencyType = str> {
+pub trait TextDocument: Document<PublicKey = PubKey> {
/// Type of associated compact document.
type CompactTextDocument_: CompactTextDocument;
--
GitLab