diff --git a/Cargo.lock b/Cargo.lock index 478913025b1d09c674a27b537a0635d3ce5cffb2..1bf7ce434008f3f266662023ecb34cd6e0219b39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,11 @@ dependencies = [ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "arrayref" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arrayvec" version = "0.4.7" @@ -86,6 +91,20 @@ name = "bitflags" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "block-buffer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byte-tools" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.2.3" @@ -170,6 +189,14 @@ name = "difference" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "digest" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "dirs" version = "1.0.2" @@ -287,7 +314,8 @@ dependencies = [ "duniter-crypto 0.2.0-a0.1", "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", @@ -463,6 +491,11 @@ dependencies = [ "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "foreign-types" version = "0.3.2" @@ -495,6 +528,14 @@ name = "gcc" version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "generic-array" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "httparse" version = "1.3.0" @@ -580,6 +621,11 @@ dependencies = [ "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "maplit" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "matches" version = "0.1.6" @@ -703,6 +749,45 @@ name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pest" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pest_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_generator 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pest_generator" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_meta 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pest_meta" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pkg-config" version = "0.3.11" @@ -900,6 +985,17 @@ dependencies = [ "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sha-1" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sha1" version = "0.6.0" @@ -1067,6 +1163,16 @@ dependencies = [ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "typenum" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ucd-trie" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ucd-util" version = "0.1.1" @@ -1198,6 +1304,7 @@ dependencies = [ [metadata] "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" "checksum backtrace 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbdd17cd962b570302f5297aea8648d5923e22e555c2ed2d8b2e34eca646bf6d" @@ -1207,6 +1314,8 @@ dependencies = [ "checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" +"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" +"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" "checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" "checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff" "checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d" @@ -1217,16 +1326,19 @@ dependencies = [ "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" +"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" "checksum dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37a76dd8b997af7107d0bb69d43903cf37153a18266f8b3fdb9911f28efb5444" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" +"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" +"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum httparse 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "422d5a93b40dbfbd8c8c24d1b4b5ef455973ef3afffc172487429fecd05bde42" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" @@ -1239,6 +1351,7 @@ dependencies = [ "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fddaa003a65722a7fb9e26b0ce95921fe4ba590542ced664d8ce2fa26f9f3ac" "checksum log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae0136257df209261daa18d6c16394757c63e032e27aafd8b07788b051082bef" +"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" @@ -1253,6 +1366,10 @@ dependencies = [ "checksum openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)" = "d8abc04833dcedef24221a91852931df2f63e3369ae003134e70aff3645775cc" "checksum pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "deb73390ab68d81992bd994d145f697451bb0b54fd39738e72eef32458ad6907" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +"checksum pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a677051ad923732bb5c70f2d45f8985a96e3eee2e2bff86697e3b11b0c3fcfde" +"checksum pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b76f477146419bc539a63f4ef40e902166cb43b3e51cecc71d9136fd12c567e7" +"checksum pest_generator 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ebee4e9680be4fd162e6f3394ae4192a6b60b1e4d17d845e631f0c68d1a3386" +"checksum pest_meta 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f6d5f6f0e6082578c86af197d780dc38328e3f768cec06aac9bc46d714e8221" "checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f" "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" "checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6" @@ -1277,6 +1394,7 @@ dependencies = [ "checksum serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)" = "92ec94e2754699adddbbc4f555791bd3acc2a2f5574cba16c93a4a9cf4a04415" "checksum serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "0a90213fa7e0f5eac3f7afe2d5ff6b088af515052cc7303bd68c7e3b91a3fb79" "checksum serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "eb40600c756f02d7ea34943626cefa85732fdae5f95b90b31f9797b3c526d1e6" +"checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum simplelog 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9cc12b39fdf4c9a07f88bffac2d628f0118ed5ac077a4b0feece61fadf1429e5" "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" @@ -1297,6 +1415,8 @@ dependencies = [ "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" +"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" +"checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" diff --git a/blockchain/apply_valid_block.rs b/blockchain/apply_valid_block.rs index 69e72f3059f5292d8f2c63110cde29a5bdaf6221..698ff0417a4ad647860439eca91948eac8989c8e 100644 --- a/blockchain/apply_valid_block.rs +++ b/blockchain/apply_valid_block.rs @@ -18,10 +18,10 @@ use duniter_dal::block::DALBlock; use duniter_dal::sources::SourceAmount; use duniter_dal::writers::requests::*; use duniter_dal::{BinDB, ForkId}; -use duniter_documents::blockchain::v10::documents::transaction::{TxAmount, TxBase}; -use duniter_documents::blockchain::v10::documents::BlockDocument; -use duniter_documents::blockchain::Document; +use duniter_documents::v10::transaction::{TxAmount, TxBase}; +use duniter_documents::v10::BlockDocument; use duniter_documents::BlockId; +use duniter_documents::Document; use durs_wot::data::{NewLinkResult, RemLinkResult}; use durs_wot::{NodeId, WebOfTrust}; use std::collections::{HashMap, HashSet}; diff --git a/blockchain/check_and_apply_block.rs b/blockchain/check_and_apply_block.rs index 3c601f47215dff775a375b3c7f6971d44d2ce3ee..8b5b7e35702f597ff6d1b38bca0431ed0bac1ce2 100644 --- a/blockchain/check_and_apply_block.rs +++ b/blockchain/check_and_apply_block.rs @@ -19,7 +19,7 @@ use apply_valid_block::*; use duniter_crypto::keys::*; use duniter_dal::block::DALBlock; use duniter_dal::*; -use duniter_documents::blockchain::Document; +use duniter_documents::Document; use duniter_documents::{BlockHash, BlockId, Blockstamp, PreviousBlockstamp}; use duniter_network::NetworkBlock; use *; diff --git a/blockchain/dbex.rs b/blockchain/dbex.rs index 34ede624a757e188ef0d2042b296e38940ed4a7d..5e7736d92789903ff3c402bf059a1bccbe068ed9 100644 --- a/blockchain/dbex.rs +++ b/blockchain/dbex.rs @@ -15,7 +15,7 @@ use duniter_crypto::keys::*; use duniter_dal::identity::DALIdentity; -use duniter_documents::blockchain::v10::documents::transaction::*; +use duniter_documents::v10::transaction::*; use duniter_module::DuniterConf; use durs_wot::data::rusty::RustyWebOfTrust; use durs_wot::operations::distance::{DistanceCalculator, WotDistance, WotDistanceParameters}; diff --git a/blockchain/lib.rs b/blockchain/lib.rs index 50397e5f7a97d6a464997bdda5545b9092fe808c..02e0a4ff21752e222bcc32fe6154eb1583a348ac 100644 --- a/blockchain/lib.rs +++ b/blockchain/lib.rs @@ -70,9 +70,9 @@ use duniter_dal::dal_requests::{DALReqBlockchain, DALRequest, DALResBlockchain, use duniter_dal::identity::DALIdentity; use duniter_dal::writers::requests::BlocksDBsWriteQuery; use duniter_dal::*; -use duniter_documents::blockchain::v10::documents::{BlockDocument, V10Document}; -use duniter_documents::blockchain::{BlockchainProtocol, Document}; +use duniter_documents::v10::{BlockDocument, V10Document}; use duniter_documents::*; +use duniter_documents::{BlockchainProtocol, Document}; use duniter_message::*; use duniter_module::*; use duniter_network::{ diff --git a/blockchain/revert_block.rs b/blockchain/revert_block.rs index 3ea7afc0bc654a0c3ea142a5fbb3766444dc4322..1492efb6ca0f1507e24a1071618775eb5e30bd1d 100644 --- a/blockchain/revert_block.rs +++ b/blockchain/revert_block.rs @@ -19,9 +19,9 @@ use duniter_dal::sources::SourceAmount; use duniter_dal::writers::requests::*; use duniter_dal::writers::transaction::DALTxV10; use duniter_dal::{BinDB, ForkId, TxV10Datas}; -use duniter_documents::blockchain::v10::documents::block::TxDocOrTxHash; -use duniter_documents::blockchain::v10::documents::transaction::{TxAmount, TxBase}; -use duniter_documents::blockchain::Document; +use duniter_documents::v10::block::TxDocOrTxHash; +use duniter_documents::v10::transaction::{TxAmount, TxBase}; +use duniter_documents::Document; use durs_wot::data::{NewLinkResult, RemLinkResult}; use durs_wot::{NodeId, WebOfTrust}; use std::collections::HashMap; diff --git a/blockchain/ts_parsers.rs b/blockchain/ts_parsers.rs index e41c1f009fd4b4bed8e0155f957e8acf4d5706f4..26e32387f0561bcab5ae62c4824235ae824747a8 100644 --- a/blockchain/ts_parsers.rs +++ b/blockchain/ts_parsers.rs @@ -18,13 +18,13 @@ extern crate sqlite; use duniter_crypto::hashs::Hash; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::block::{BlockV10Parameters, TxDocOrTxHash}; -use duniter_documents::blockchain::v10::documents::identity::IdentityDocumentBuilder; -use duniter_documents::blockchain::v10::documents::membership::*; -use duniter_documents::blockchain::v10::documents::transaction::*; -use duniter_documents::blockchain::v10::documents::*; -use duniter_documents::blockchain::DocumentBuilder; +use duniter_documents::v10::block::{BlockV10Parameters, TxDocOrTxHash}; +use duniter_documents::v10::identity::*; +use duniter_documents::v10::membership::*; +use duniter_documents::v10::transaction::*; +use duniter_documents::v10::*; use duniter_documents::CurrencyName; +use duniter_documents::DocumentBuilder; use duniter_documents::{BlockHash, BlockId, Blockstamp}; use duniter_network::{NetworkBlock, NetworkBlockV10}; use std::str::FromStr; @@ -329,7 +329,7 @@ pub fn parse_transaction( let mut inputs = Vec::with_capacity(inputs_array.len()); for input in inputs_array { let input_str = input.as_str()?; - match TransactionInput::parse_from_str(input_str) { + match TransactionInput::from_str(input_str) { Ok(input) => inputs.push(input), Err(_) => { return None; @@ -339,7 +339,7 @@ pub fn parse_transaction( let unlocks_array = source.get("unlocks")?.as_array()?; let mut unlocks = Vec::with_capacity(unlocks_array.len()); for unlock in unlocks_array { - match TransactionInputUnlocks::parse_from_str(unlock.as_str()?) { + match TransactionInputUnlocks::from_str(unlock.as_str()?) { Ok(unlock) => unlocks.push(unlock), Err(_) => { return None; @@ -350,7 +350,7 @@ pub fn parse_transaction( let mut outputs = Vec::with_capacity(outputs_array.len()); for output in outputs_array { outputs.push( - TransactionOutput::parse_from_str( + TransactionOutput::from_str( output .as_str() .unwrap_or_else(|| panic!("Fail to parse output : {:?}", output)), diff --git a/dal/block.rs b/dal/block.rs index 5a35d938ac91cfa05385839b3208c6acf3953228..2dc072dd9194460311d26988127d36c6cb55f13c 100644 --- a/dal/block.rs +++ b/dal/block.rs @@ -15,8 +15,8 @@ use super::constants::MAX_FORKS; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::BlockDocument; -use duniter_documents::blockchain::Document; +use duniter_documents::v10::BlockDocument; +use duniter_documents::Document; use duniter_documents::{BlockHash, BlockId, Blockstamp, PreviousBlockstamp}; use durs_wot::NodeId; use std::collections::HashMap; diff --git a/dal/currency_params.rs b/dal/currency_params.rs index e0ab8a0ce3d4474036c780b5660b5b8a01d7294e..5b902385b2b6b41658279da0027fd56bd8852784 100644 --- a/dal/currency_params.rs +++ b/dal/currency_params.rs @@ -14,7 +14,7 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. use constants::*; -use duniter_documents::blockchain::v10::documents::block::BlockV10Parameters; +use duniter_documents::v10::block::BlockV10Parameters; use duniter_documents::CurrencyName; use *; diff --git a/dal/dal_event.rs b/dal/dal_event.rs index cdc27e5e97d70bfdd6ae6b275b49a78797409bd6..9a487dee7ff9337a133e88a79eba1e9d07376f9f 100644 --- a/dal/dal_event.rs +++ b/dal/dal_event.rs @@ -13,9 +13,8 @@ // 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 duniter_documents::blockchain::v10::documents::BlockDocument; -use duniter_documents::blockchain::BlockchainProtocol; -use duniter_documents::Blockstamp; +use duniter_documents::v10::block::BlockDocument; +use duniter_documents::*; #[derive(Debug, Clone)] /// Event to be transmitted to the other modules diff --git a/dal/dal_requests.rs b/dal/dal_requests.rs index 52fc8383f1bacf147dad27372376629fd7d3951d..9a3a8604595602ffaea196588eb40540a28dcec7 100644 --- a/dal/dal_requests.rs +++ b/dal/dal_requests.rs @@ -19,9 +19,11 @@ extern crate serde; use self::duniter_module::ModuleReqId; use duniter_crypto::hashs::Hash; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::{ - BlockDocument, CertificationDocument, IdentityDocument, MembershipDocument, RevocationDocument, -}; +use duniter_documents::v10::block::BlockDocument; +use duniter_documents::v10::certification::CertificationDocument; +use duniter_documents::v10::identity::IdentityDocument; +use duniter_documents::v10::membership::MembershipDocument; +use duniter_documents::v10::revocation::RevocationDocument; use duniter_documents::Blockstamp; use std::collections::HashMap; diff --git a/dal/identity.rs b/dal/identity.rs index 30d36b4e7b0ccd0392085948173f18d9210a25c9..86dad5ac355d5754bde64b7fd585a5e7dffc788a 100644 --- a/dal/identity.rs +++ b/dal/identity.rs @@ -15,7 +15,7 @@ use currency_params::CurrencyParameters; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::IdentityDocument; +use duniter_documents::v10::identity::IdentityDocument; use duniter_documents::{BlockId, Blockstamp}; use durs_wot::NodeId; use std::collections::HashMap; diff --git a/dal/lib.rs b/dal/lib.rs index b0181eb049e78eeb8e0a89378894edacc80286fb..07093a9a59880a41ba9e73f1f7e2628ca9d7fb17 100644 --- a/dal/lib.rs +++ b/dal/lib.rs @@ -81,8 +81,8 @@ pub mod writers; use duniter_crypto::hashs::Hash; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::block::BlockV10Parameters; -use duniter_documents::blockchain::v10::documents::transaction::*; +use duniter_documents::v10::block::BlockV10Parameters; +use duniter_documents::v10::transaction::*; use duniter_documents::CurrencyName; use duniter_documents::{BlockHash, BlockId, Blockstamp, PreviousBlockstamp}; use durs_wot::{NodeId, WebOfTrust}; diff --git a/dal/parsers/certifications.rs b/dal/parsers/certifications.rs index 675894f56f4e211e49d4902b98e6ed217d04545c..e575398682c7a32e5dea0efae6627a87d95b3016 100644 --- a/dal/parsers/certifications.rs +++ b/dal/parsers/certifications.rs @@ -17,8 +17,8 @@ extern crate serde; extern crate serde_json; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::certification::CompactCertificationDocument; -use duniter_documents::blockchain::v10::documents::{CertificationDocument, TextDocumentFormat}; +use duniter_documents::v10::certification::{CertificationDocument, CompactCertificationDocument}; +use duniter_documents::v10::TextDocumentFormat; use duniter_documents::BlockId; /// Parse array of certification json documents into vector of `CompactCertificationDocument` diff --git a/dal/parsers/revoked.rs b/dal/parsers/revoked.rs index 03779cdfc6cdd98e47f9407cd86bd549f6a1947a..2b22e996e14ccd8026a8eba8d66c9874de117cc3 100644 --- a/dal/parsers/revoked.rs +++ b/dal/parsers/revoked.rs @@ -16,8 +16,8 @@ extern crate serde_json; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::revocation::CompactRevocationDocument; -use duniter_documents::blockchain::v10::documents::{RevocationDocument, TextDocumentFormat}; +use duniter_documents::v10::revocation::{CompactRevocationDocument, RevocationDocument}; +use duniter_documents::v10::TextDocumentFormat; /// Parse array of revocations json documents into vector of `CompactRevocationDocument` pub fn parse_revocations_into_compact( diff --git a/dal/sources.rs b/dal/sources.rs index 54a40a54ff021c8d698c78d05d9e3ec340e4c184..8d020059eb31a2927e15478f5c98c339640bd94d 100644 --- a/dal/sources.rs +++ b/dal/sources.rs @@ -18,7 +18,7 @@ extern crate duniter_documents; use duniter_crypto::hashs::Hash; use duniter_crypto::keys::PubKey; -use duniter_documents::blockchain::v10::documents::transaction::*; +use duniter_documents::v10::transaction::*; use duniter_documents::BlockId; use std::cmp::Ordering; use std::ops::{Add, Sub}; diff --git a/dal/writers/block.rs b/dal/writers/block.rs index d447ad41666b55d09ebb301e736b9c21a422b59a..a716aa4473228376a676da7f86120fbb247549b3 100644 --- a/dal/writers/block.rs +++ b/dal/writers/block.rs @@ -14,7 +14,7 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. use block::DALBlock; -use duniter_documents::blockchain::Document; +use duniter_documents::Document; use duniter_documents::{BlockHash, BlockId, PreviousBlockstamp}; use std::collections::HashMap; use ForkId; diff --git a/dal/writers/certification.rs b/dal/writers/certification.rs index bb01dfd1a793267f7907515312a24944a98f3335..bb61ffe80b7ffd6c638ca3c9f66cd3c653f43ace 100644 --- a/dal/writers/certification.rs +++ b/dal/writers/certification.rs @@ -18,7 +18,7 @@ extern crate serde_json; use currency_params::CurrencyParameters; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::certification::CompactCertificationDocument; +use duniter_documents::v10::certification::CompactCertificationDocument; use duniter_documents::BlockId; use durs_wot::NodeId; use {BinDB, CertsExpirV10Datas, DALError, IdentitiesV10Datas}; diff --git a/dal/writers/dividend.rs b/dal/writers/dividend.rs index 648240fbecc6b8c7d9b86a8a99efe78f3b87d9d3..4b2b97a283e93a2556dd025be4b112d3b42ebfa8 100644 --- a/dal/writers/dividend.rs +++ b/dal/writers/dividend.rs @@ -14,7 +14,7 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. use duniter_crypto::keys::PubKey; -use duniter_documents::blockchain::v10::documents::transaction::*; +use duniter_documents::v10::transaction::*; use duniter_documents::BlockId; use sources::SourceAmount; use std::collections::{HashMap, HashSet}; diff --git a/dal/writers/identity.rs b/dal/writers/identity.rs index 93f2bef0b3936c7c04803aa4ef9664504b4e815d..a491d0060d6446ca315993e16b522f93e2d85508 100644 --- a/dal/writers/identity.rs +++ b/dal/writers/identity.rs @@ -15,8 +15,8 @@ use currency_params::CurrencyParameters; use duniter_crypto::keys::PubKey; -use duniter_documents::blockchain::v10::documents::IdentityDocument; -use duniter_documents::blockchain::Document; +use duniter_documents::v10::identity::IdentityDocument; +use duniter_documents::Document; use duniter_documents::{BlockId, Blockstamp}; use durs_wot::NodeId; use identity::{DALIdentity, DALIdentityState}; diff --git a/dal/writers/requests.rs b/dal/writers/requests.rs index 825a14af3f91f04f5359f3f0b0fc8783ff7d44bc..5e00a01d9076c33e5f2c7a6011a6a80b6485883b 100644 --- a/dal/writers/requests.rs +++ b/dal/writers/requests.rs @@ -19,8 +19,8 @@ extern crate serde_json; use block::DALBlock; use currency_params::CurrencyParameters; use duniter_crypto::keys::PubKey; -use duniter_documents::blockchain::v10::documents::certification::CompactCertificationDocument; -use duniter_documents::blockchain::v10::documents::identity::IdentityDocument; +use duniter_documents::v10::certification::CompactCertificationDocument; +use duniter_documents::v10::identity::IdentityDocument; use duniter_documents::Blockstamp; use durs_wot::NodeId; use identity::DALIdentity; diff --git a/dal/writers/transaction.rs b/dal/writers/transaction.rs index b0733ebe4ef73a29fd9aed9233e478ec3973dd6f..a7c23d1ff9d7881ff4ec7134b67ec9fa387101bb 100644 --- a/dal/writers/transaction.rs +++ b/dal/writers/transaction.rs @@ -13,7 +13,8 @@ // 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 duniter_documents::blockchain::v10::documents::transaction::*; +use duniter_documents::v10::transaction::*; + use sources::{SourceAmount, SourceIndexV10, UTXOIndexV10, UTXOV10}; use *; @@ -413,7 +414,8 @@ pub fn apply_and_write_tx( #[cfg(test)] mod tests { use super::*; - use duniter_documents::blockchain::{Document, DocumentBuilder, VerificationResult}; + use duniter_documents::{Document, DocumentBuilder, VerificationResult}; + use std::str::FromStr; fn build_first_tx_of_g1() -> TransactionDocument { let pubkey = PubKey::Ed25519( @@ -432,18 +434,19 @@ mod tests { blockstamp: &block, locktime: &0, issuers: &vec![pubkey], - inputs: &vec![TransactionInput::parse_from_str( + inputs: &vec![TransactionInput::from_str( "1000:0:D:2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ:1", ) .expect("fail to parse input !")], - unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)") - .expect("fail to parse unlock !")], + unlocks: &vec![ + TransactionInputUnlocks::from_str("0:SIG(0)").expect("fail to parse unlock !") + ], outputs: &vec![ - TransactionOutput::parse_from_str( + TransactionOutput::from_str( "1:0:SIG(Com8rJukCozHZyFao6AheSsfDQdPApxQRnz7QYFf64mm)", ) .expect("fail to parse output !"), - TransactionOutput::parse_from_str( + TransactionOutput::from_str( "999:0:SIG(2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ)", ) .expect("fail to parse output !"), diff --git a/documents/Cargo.toml b/documents/Cargo.toml index 0f6fd6ff01c1ff0d37fab7097e9a8d19ec22358e..a0633f8044ce03868f2794803e7c5b179efa1641 100644 --- a/documents/Cargo.toml +++ b/documents/Cargo.toml @@ -9,7 +9,7 @@ keywords = ["duniter", "blockchain", "cryptocurrency", "document"] license = "AGPL-3.0" [lib] -path = "lib.rs" +path = "src/lib.rs" [dependencies] base58 = "0.1.*" @@ -18,7 +18,8 @@ byteorder = "1.2.3" duniter-crypto = { path = "../crypto" } lazy_static = "1.0.*" linked-hash-map = "0.5.*" -regex = "1.0.*" +pest = "2.0" +pest_derive = "2.0" rust-crypto = "0.2.*" serde = "1.0.*" serde_derive = "1.0.*" diff --git a/documents/blockchain/v10/mod.rs b/documents/blockchain/v10/mod.rs deleted file mode 100644 index 9b3d159d6d576877e01a5822ed3e720793bb3775..0000000000000000000000000000000000000000 --- a/documents/blockchain/v10/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// 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/>. - -//! Provide wrappers around Duniter V10 documents and events. - -pub mod documents; diff --git a/documents/lib.rs b/documents/lib.rs deleted file mode 100644 index 04f20fac89bd112f3273fd01787a3d5ac0923b98..0000000000000000000000000000000000000000 --- a/documents/lib.rs +++ /dev/null @@ -1,271 +0,0 @@ -// 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/>. - -//! Implements the Duniter Documents Protocol. - -#![cfg_attr(feature = "strict", deny(warnings))] -#![deny( - missing_docs, - missing_debug_implementations, - missing_copy_implementations, - trivial_casts, - trivial_numeric_casts, - unsafe_code, - unstable_features, - unused_import_braces, - unused_qualifications -)] - -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate serde_derive; - -extern crate base58; -extern crate base64; -extern crate byteorder; -extern crate crypto; -extern crate duniter_crypto; -extern crate linked_hash_map; -extern crate regex; -extern crate serde; - -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; -use currencies_codes::*; -use duniter_crypto::hashs::Hash; -use std::cmp::Ordering; -use std::fmt::{Debug, Display, Error, Formatter}; -use std::io::Cursor; -use std::mem; - -pub mod blockchain; -mod currencies_codes; - -/// Currency name -#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)] -pub struct CurrencyName(pub String); - -impl Default for CurrencyName { - fn default() -> CurrencyName { - CurrencyName(String::from("default_currency")) - } -} - -impl Display for CurrencyName { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - write!(f, "{}", self.0) - } -} - -/// CurrencyCodeError -#[derive(Debug)] -pub enum CurrencyCodeError { - /// UnknowCurrencyCode - UnknowCurrencyCode(), - /// IoError - IoError(::std::io::Error), - /// UnknowCurrencyName - UnknowCurrencyName(), -} - -impl From<::std::io::Error> for CurrencyCodeError { - fn from(error: ::std::io::Error) -> Self { - CurrencyCodeError::IoError(error) - } -} - -impl CurrencyName { - /// Convert bytes to CurrencyName - pub fn from(currency_code: [u8; 2]) -> Result<Self, CurrencyCodeError> { - let mut currency_code_bytes = Cursor::new(currency_code.to_vec()); - let currency_code = currency_code_bytes.read_u16::<BigEndian>()?; - Self::from_u16(currency_code) - } - /// Convert u16 to CurrencyName - pub fn from_u16(currency_code: u16) -> Result<Self, CurrencyCodeError> { - match currency_code { - tmp if tmp == *CURRENCY_NULL => Ok(CurrencyName(String::from(""))), - tmp if tmp == *CURRENCY_G1 => Ok(CurrencyName(String::from("g1"))), - tmp if tmp == *CURRENCY_G1_TEST => Ok(CurrencyName(String::from("g1-test"))), - _ => Err(CurrencyCodeError::UnknowCurrencyCode()), - } - } - /// Convert CurrencyName to bytes - pub fn to_bytes(&self) -> Result<[u8; 2], CurrencyCodeError> { - let currency_code = match self.0.as_str() { - "g1" => *CURRENCY_G1, - "g1-test" => *CURRENCY_G1_TEST, - _ => return Err(CurrencyCodeError::UnknowCurrencyName()), - }; - let mut buffer = [0u8; mem::size_of::<u16>()]; - buffer - .as_mut() - .write_u16::<BigEndian>(currency_code) - .expect("Unable to write"); - Ok(buffer) - } -} - -/// A block Id. -#[derive(Copy, Clone, Debug, Deserialize, Ord, PartialEq, PartialOrd, Eq, Hash, Serialize)] -pub struct BlockId(pub u32); - -impl Display for BlockId { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - write!(f, "{}", self.0) - } -} - -/// Wrapper of a block hash. -#[derive(Copy, Clone, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Hash, Serialize)] -pub struct BlockHash(pub Hash); - -impl Display for BlockHash { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - write!(f, "{}", self.0.to_hex()) - } -} - -impl Debug for BlockHash { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - write!(f, "BlockHash({})", self) - } -} - -/// Type of errors for [`BlockUId`] parsing. -/// -/// [`BlockUId`]: struct.BlockUId.html -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum BlockUIdParseError { - /// Given string have invalid format - InvalidFormat(), - /// [`BlockId`](struct.BlockHash.html) part is not a valid number. - InvalidBlockId(), - /// [`BlockHash`](struct.BlockHash.html) part is not a valid hex number. - InvalidBlockHash(), -} - -/// A blockstamp (Unique ID). -/// -/// It's composed of the [`BlockId`] and -/// the [`BlockHash`] of the block. -/// -/// Thanks to blockchain immutability and frequent block production, it can -/// be used to date information. -/// -/// [`BlockId`]: struct.BlockId.html -/// [`BlockHash`]: struct.BlockHash.html - -#[derive(Copy, Clone, Deserialize, PartialEq, Eq, Hash, Serialize)] -pub struct Blockstamp { - /// Block Id. - pub id: BlockId, - /// Block hash. - pub hash: BlockHash, -} - -/// Previous blockstamp (BlockId-1, previous_hash) -pub type PreviousBlockstamp = Blockstamp; - -impl Blockstamp { - /// Blockstamp size (in bytes). - pub const SIZE_IN_BYTES: usize = 36; -} - -impl Display for Blockstamp { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - write!(f, "{}-{}", self.id, self.hash) - } -} - -impl Debug for Blockstamp { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - write!(f, "BlockUId({})", self) - } -} - -impl Default for Blockstamp { - fn default() -> Blockstamp { - Blockstamp { - id: BlockId(0), - hash: BlockHash(Hash::default()), - } - } -} - -impl PartialOrd for Blockstamp { - fn partial_cmp(&self, other: &Blockstamp) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for Blockstamp { - fn cmp(&self, other: &Blockstamp) -> Ordering { - if self.id == other.id { - self.hash.cmp(&other.hash) - } else { - self.id.cmp(&other.id) - } - } -} - -#[derive(Debug)] -/// Error when converting a byte vector to Blockstamp -pub enum ReadBytesBlockstampError { - /// Bytes vector is too short - TooShort(), - /// Bytes vector is too long - TooLong(), - /// IoError - IoError(::std::io::Error), -} - -impl From<::std::io::Error> for ReadBytesBlockstampError { - fn from(e: ::std::io::Error) -> Self { - ReadBytesBlockstampError::IoError(e) - } -} - -impl Blockstamp { - /// Create a `BlockUId` from a text. - pub fn from_string(src: &str) -> Result<Blockstamp, BlockUIdParseError> { - let mut split = src.split('-'); - - if split.clone().count() != 2 { - Err(BlockUIdParseError::InvalidFormat()) - } else { - let id = split.next().unwrap().parse::<u32>(); - let hash = Hash::from_hex(split.next().unwrap()); - - if id.is_err() { - Err(BlockUIdParseError::InvalidBlockId()) - } else if hash.is_err() { - Err(BlockUIdParseError::InvalidBlockHash()) - } else { - Ok(Blockstamp { - id: BlockId(id.unwrap()), - hash: BlockHash( - hash.expect("Try to get hash of an uncompleted or reduce block !"), - ), - }) - } - } - } - - /// Convert a `BlockUId` to its text format. - pub fn to_string(&self) -> String { - format!("{}", self) - } -} diff --git a/documents/src/blockstamp.rs b/documents/src/blockstamp.rs new file mode 100644 index 0000000000000000000000000000000000000000..a81d70af7bfbfd866fb3ebdc81ef9cf86fc65fd5 --- /dev/null +++ b/documents/src/blockstamp.rs @@ -0,0 +1,144 @@ +// 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/>. + +//! Wrapper for blockstamp + +use *; + +/// Type of errors for [`BlockUId`] parsing. +/// +/// [`BlockUId`]: struct.BlockUId.html +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum BlockstampParseError { + /// Given string have invalid format + InvalidFormat(), + /// [`BlockId`](struct.BlockHash.html) part is not a valid number. + InvalidBlockId(), + /// [`BlockHash`](struct.BlockHash.html) part is not a valid hex number. + InvalidBlockHash(), +} + +/// A blockstamp (Unique ID). +/// +/// It's composed of the [`BlockId`] and +/// the [`BlockHash`] of the block. +/// +/// Thanks to blockchain immutability and frequent block production, it can +/// be used to date information. +/// +/// [`BlockId`]: struct.BlockId.html +/// [`BlockHash`]: struct.BlockHash.html + +#[derive(Copy, Clone, Deserialize, PartialEq, Eq, Hash, Serialize)] +pub struct Blockstamp { + /// Block Id. + pub id: BlockId, + /// Block hash. + pub hash: BlockHash, +} + +/// Previous blockstamp (BlockId-1, previous_hash) +pub type PreviousBlockstamp = Blockstamp; + +impl Blockstamp { + /// Blockstamp size (in bytes). + pub const SIZE_IN_BYTES: usize = 36; +} + +impl Display for Blockstamp { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + write!(f, "{}-{}", self.id, self.hash) + } +} + +impl Debug for Blockstamp { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + write!(f, "BlockUId({})", self) + } +} + +impl Default for Blockstamp { + fn default() -> Blockstamp { + Blockstamp { + id: BlockId(0), + hash: BlockHash(Hash::default()), + } + } +} + +impl PartialOrd for Blockstamp { + fn partial_cmp(&self, other: &Blockstamp) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for Blockstamp { + fn cmp(&self, other: &Blockstamp) -> Ordering { + if self.id == other.id { + self.hash.cmp(&other.hash) + } else { + self.id.cmp(&other.id) + } + } +} + +#[derive(Debug)] +/// Error when converting a byte vector to Blockstamp +pub enum ReadBytesBlockstampError { + /// Bytes vector is too short + TooShort(), + /// Bytes vector is too long + TooLong(), + /// IoError + IoError(::std::io::Error), +} + +impl From<::std::io::Error> for ReadBytesBlockstampError { + fn from(e: ::std::io::Error) -> Self { + ReadBytesBlockstampError::IoError(e) + } +} + +impl Blockstamp { + /// Create a `BlockUId` from a text. + pub fn from_string(src: &str) -> Result<Blockstamp, BlockstampParseError> { + let mut split = src.split('-'); + + if split.clone().count() != 2 { + Err(BlockstampParseError::InvalidFormat()) + } else { + let id = split.next().unwrap().parse::<u32>(); + let hash = Hash::from_hex(split.next().unwrap()); + + if id.is_err() { + Err(BlockstampParseError::InvalidBlockId()) + } else if hash.is_err() { + Err(BlockstampParseError::InvalidBlockHash()) + } else { + Ok(Blockstamp { + id: BlockId(id.unwrap()), + hash: BlockHash( + hash.expect("Try to get hash of an uncompleted or reduce block !"), + ), + }) + } + } + } + + /// Convert a `BlockUId` to its text format. + pub fn to_string(&self) -> String { + format!("{}", self) + } +} diff --git a/documents/currencies_codes.rs b/documents/src/currencies_codes.rs similarity index 100% rename from documents/currencies_codes.rs rename to documents/src/currencies_codes.rs diff --git a/documents/src/documents_grammar.pest b/documents/src/documents_grammar.pest new file mode 100644 index 0000000000000000000000000000000000000000..cc509f5f63eb02674d7660f57081eff17e5b8dd4 --- /dev/null +++ b/documents/src/documents_grammar.pest @@ -0,0 +1,162 @@ +nl = _{ "\n" } +hexa = { ASCII_DIGIT | 'A'..'F' } +base58 = { !("O" | "I" | "l") ~ ASCII_ALPHANUMERIC } +base64 = { ASCII_ALPHANUMERIC | "+" | "/" } + +integer = @{ "0" | ('1'..'9' ~ ASCII_DIGIT*) } +hash = @{ hexa{64} } + +currency = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "-" | "_")* } +pubkey = @{ base58{43,44} } +uid = @{ ASCII_ALPHA+ } +block_id = @{ integer } +blockstamp = ${ block_id ~ "-" ~ hash } +ed25519_sig = @{ base64{86,88} ~ "="{0,2} } + +v10 = _{ "Version: 10" } + +idty_v10 = ${ + v10 ~ nl ~ + "Type: Identity" ~ nl ~ + "Currency: " ~ currency ~ nl ~ + "Issuer: " ~ pubkey ~ nl ~ + "UniqueID: " ~ uid ~ nl ~ + "Timestamp: " ~ blockstamp ~ nl ~ + ed25519_sig? ~ nl* +} + +idty = ${ + SOI ~ + (&(v10 ~ nl) ~ idty_v10) + ~ EOI +} + +membership_in = @{ "IN" } +membership_out = @{ "OUT" } + +membership_v10 = ${ + v10 ~ nl ~ + "Type: Membership" ~ nl ~ + "Currency: " ~ currency ~ nl ~ + "Issuer: " ~ pubkey ~ nl ~ + "Block: " ~ blockstamp ~ nl ~ + "Membership: " ~ (membership_in | membership_out) ~ nl ~ + "UserID: " ~ uid ~ nl ~ + "CertTS: " ~ blockstamp ~ nl ~ + ed25519_sig? ~ nl* +} + +membership = ${ + SOI ~ + (&("Version: 10" ~ nl) ~ membership_v10) + ~ EOI +} + +cert_v10 = ${ + v10 ~ nl ~ + "Type: Certification" ~ nl ~ + "Currency: " ~ currency ~ nl ~ + "Issuer: " ~ pubkey ~ nl ~ + "IdtyIssuer: " ~ pubkey ~ nl ~ + "IdtyUniqueID: " ~ uid ~ nl ~ + "IdtyTimestamp: " ~ blockstamp ~ nl ~ + "IdtySignature: " ~ ed25519_sig ~ nl ~ + "CertTimestamp: " ~ blockstamp ~ nl ~ + ed25519_sig? ~ nl* +} + +cert = ${ + SOI ~ + (&("Version: 10" ~ nl) ~ cert_v10) + ~ EOI +} + +revoc_v10 = ${ + v10 ~ nl ~ + "Type: Revocation" ~ nl ~ + "Currency: " ~ currency ~ nl ~ + "Issuer: " ~ pubkey ~ nl ~ + "IdtyUniqueID: " ~ uid ~ nl ~ + "IdtyTimestamp: " ~ blockstamp ~ nl ~ + "IdtySignature: " ~ ed25519_sig ~ nl ~ + ed25519_sig? ~ nl* +} + +revoc = ${ + SOI ~ + (&("Version: 10" ~ nl) ~ revoc_v10) + ~ EOI +} + +tx_locktime = @{ integer } +tx_amount = @{ integer } +tx_amount_base = @{ integer } +du_block_id = @{ integer } +tx_index = @{ integer } +input_index = @{ integer } +issuer_index = @{ integer } +xhx_secret = @ { ASCII_ALPHANUMERIC+ } +csv_duration = @{ integer } +cltv_timestamp = @{ integer } + +tx_input = ${ tx_input_du | tx_input_tx } +tx_input_du = ${ tx_amount ~ ":" ~ tx_amount_base ~ ":D:" ~ pubkey ~ ":" ~ du_block_id } +tx_input_tx = ${ tx_amount ~ ":" ~ tx_amount_base ~ ":T:" ~ hash ~ ":" ~ tx_index } + +tx_unlock = ${ input_index ~ ":" ~ unlock_cond ~ (" " ~ unlock_cond)* } +unlock_cond = _{ unlock_sig | unlock_xhx } +unlock_sig = ${ "SIG(" ~ issuer_index ~ ")" } +unlock_xhx = ${ "XHX(" ~ xhx_secret ~ ")" } + +tx_output = ${ tx_amount ~ ":" ~ tx_amount_base ~ ":" ~ output_conds_group } +output_conds_group = _{ output_and_group | output_or_group | output_single_cond } +output_and_group = ${ "(" ~ output_conds_group ~ (" && " ~ output_conds_group)+ ~ ")" } +output_or_group = ${ "(" ~ output_conds_group ~ (" || " ~ output_conds_group)+ ~ ")" } +output_single_cond = _{ output_cond_sig | output_cond_xhx | output_cond_csv | output_cond_cltv } +output_cond_sig = ${ "SIG(" ~ pubkey ~ ")"? } +output_cond_xhx = ${ "XHX(" ~ hash ~ ")"? } +output_cond_csv = ${ "CSV(" ~ csv_duration ~ ")"? } +output_cond_cltv = ${ "CLTV(" ~ cltv_timestamp ~ ")"? } + +tx_comment_char = { + ASCII_ALPHANUMERIC | "\\" | ":" | "/" | ";" | "*" | "[" | "]" | "(" | ")" | "?" | "!" | "^" + | "+" | "=" | "@" | "&" | "~" | "#" | "{" | "}" | "|" | "<" | ">" | "%" | "." | " " | "-" +} +tx_comment = @{ tx_comment_char{0,255} } + +tx_v10 = ${ + "Version: 10" ~ nl ~ + "Type: Transaction" ~ nl ~ + "Currency: " ~ currency ~ nl ~ + "Blockstamp: " ~ blockstamp ~ nl ~ + "Locktime: " ~ tx_locktime ~ nl ~ + "Issuers:" ~ nl ~ (pubkey ~ nl)+ ~ + "Inputs:" ~ nl ~ (tx_input ~ nl)+ ~ + "Unlocks:" ~ nl ~ (tx_unlock ~ nl)+ ~ + "Outputs:" ~ nl ~ (tx_output ~ nl)+ ~ + "Comment: " ~ tx_comment ~ nl ~ + (ed25519_sig ~ nl)* ~ // intermediate signatures (zero if the transaction has only one signature) + ed25519_sig? ~ nl* // last signature +} + +tx = ${ + SOI ~ + (&("Version: 10" ~ nl) ~ tx_v10) + ~ EOI +} + +document_v10 = ${ + SOI ~ + (&"Type: Identity" ~ idty_v10) | + (&"Type: Membership" ~ membership_v10) | + (&"Type: Certification" ~ cert_v10) | + (&"Type: Revocation" ~ revoc_v10) | + (&"Type: Transaction" ~ tx_v10) + ~ EOI +} + +document = ${ + SOI ~ + (&("Version: 10" ~ nl) ~ document_v10) + ~ EOI +} diff --git a/documents/blockchain/mod.rs b/documents/src/lib.rs similarity index 54% rename from documents/blockchain/mod.rs rename to documents/src/lib.rs index 64edf826a48de9a18793acf829dde9dd8735e0bd..9ee020c3aa4625c09ee271f26064f3c97f3f53b2 100644 --- a/documents/blockchain/mod.rs +++ b/documents/src/lib.rs @@ -13,25 +13,152 @@ // 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/>. -//! Provide wrappers around Duniter documents and events. - -use std::fmt::Debug; +//! Implements the Duniter Documents Protocol. + +#![cfg_attr(feature = "strict", deny(warnings))] +#![deny( + missing_debug_implementations, + missing_copy_implementations, + trivial_casts, + trivial_numeric_casts, + unsafe_code, + unstable_features, + unused_import_braces +)] + +extern crate base58; +extern crate base64; +extern crate byteorder; +extern crate crypto; +extern crate duniter_crypto; +extern crate linked_hash_map; +extern crate pest; +#[macro_use] +extern crate pest_derive; +extern crate serde; +#[macro_use] +extern crate serde_derive; + +pub mod blockstamp; +mod currencies_codes; +pub mod v10; -use duniter_crypto::keys::{PrivateKey, PublicKey}; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use currencies_codes::*; +use duniter_crypto::hashs::Hash; +use duniter_crypto::keys::*; +use std::cmp::Ordering; +use std::fmt::{Debug, Display, Error, Formatter}; +use std::io::Cursor; +use std::mem; -use super::Blockstamp; +pub use blockstamp::{Blockstamp, PreviousBlockstamp}; -pub mod v10; +#[derive(Parser)] +#[grammar = "documents_grammar.pest"] +/// Parser for Documents +struct DocumentsParser; /// List of blockchain protocol versions. #[derive(Debug, Clone)] pub enum BlockchainProtocol { /// Version 10. - V10(Box<v10::documents::V10Document>), + V10(Box<v10::V10Document>), /// Version 11. (not done yet, but defined for tests) V11(), } +/// Currency name +#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)] +pub struct CurrencyName(pub String); + +impl Default for CurrencyName { + fn default() -> CurrencyName { + CurrencyName(String::from("default_currency")) + } +} + +impl Display for CurrencyName { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + write!(f, "{}", self.0) + } +} + +/// CurrencyCodeError +#[derive(Debug)] +pub enum CurrencyCodeError { + /// UnknowCurrencyCode + UnknowCurrencyCode(), + /// IoError + IoError(::std::io::Error), + /// UnknowCurrencyName + UnknowCurrencyName(), +} + +impl From<::std::io::Error> for CurrencyCodeError { + fn from(error: ::std::io::Error) -> Self { + CurrencyCodeError::IoError(error) + } +} + +impl CurrencyName { + /// Convert bytes to CurrencyName + pub fn from(currency_code: [u8; 2]) -> Result<Self, CurrencyCodeError> { + let mut currency_code_bytes = Cursor::new(currency_code.to_vec()); + let currency_code = currency_code_bytes.read_u16::<BigEndian>()?; + Self::from_u16(currency_code) + } + /// Convert u16 to CurrencyName + pub fn from_u16(currency_code: u16) -> Result<Self, CurrencyCodeError> { + match currency_code { + tmp if tmp == *CURRENCY_NULL => Ok(CurrencyName(String::from(""))), + tmp if tmp == *CURRENCY_G1 => Ok(CurrencyName(String::from("g1"))), + tmp if tmp == *CURRENCY_G1_TEST => Ok(CurrencyName(String::from("g1-test"))), + _ => Err(CurrencyCodeError::UnknowCurrencyCode()), + } + } + /// Convert CurrencyName to bytes + pub fn to_bytes(&self) -> Result<[u8; 2], CurrencyCodeError> { + let currency_code = match self.0.as_str() { + "g1" => *CURRENCY_G1, + "g1-test" => *CURRENCY_G1_TEST, + _ => return Err(CurrencyCodeError::UnknowCurrencyName()), + }; + let mut buffer = [0u8; mem::size_of::<u16>()]; + buffer + .as_mut() + .write_u16::<BigEndian>(currency_code) + .expect("Unable to write"); + Ok(buffer) + } +} + +/// A block Id. +#[derive(Copy, Clone, Debug, Deserialize, Ord, PartialEq, PartialOrd, Eq, Hash, Serialize)] +pub struct BlockId(pub u32); + +impl Display for BlockId { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + write!(f, "{}", self.0) + } +} + +/// Wrapper of a block hash. +#[derive(Copy, Clone, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Hash, Serialize)] +pub struct BlockHash(pub Hash); + +impl Display for BlockHash { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + write!(f, "{}", self.0.to_hex()) + } +} + +impl Debug for BlockHash { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + write!(f, "BlockHash({})", self) + } +} + /// trait providing commun methods for any documents of any protocol version. /// /// # Design choice @@ -139,134 +266,3 @@ pub trait DocumentParser<S, D, E> { /// Parse a source and return a document or an error. fn parse(source: S) -> Result<D, E>; } - -#[cfg(test)] -mod tests { - use super::*; - use duniter_crypto::keys::*; - - // simple text document for signature testing - #[derive(Debug, Clone)] - struct PlainTextDocument { - pub text: &'static str, - pub issuers: Vec<PubKey>, - pub signatures: Vec<Sig>, - } - - impl Document for PlainTextDocument { - type PublicKey = PubKey; - type CurrencyType = str; - - fn version(&self) -> u16 { - unimplemented!() - } - - fn currency(&self) -> &str { - unimplemented!() - } - - fn blockstamp(&self) -> Blockstamp { - unimplemented!() - } - - fn issuers(&self) -> &Vec<PubKey> { - &self.issuers - } - - fn signatures(&self) -> &Vec<Sig> { - &self.signatures - } - - fn as_bytes(&self) -> &[u8] { - self.text.as_bytes() - } - } - - #[test] - fn verify_signatures() { - let text = "Version: 10 -Type: Identity -Currency: duniter_unit_test_currency -Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV -UniqueID: tic -Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -"; - - // good pair - let issuer1 = PubKey::Ed25519( - ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV") - .unwrap(), - ); - - let sig1 = Sig::Ed25519( - ed25519::Signature::from_base64( - "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\ - mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==", - ) - .unwrap(), - ); - - // incorrect pair - let issuer2 = PubKey::Ed25519( - ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt32bzHbA3NJR46DeQYCS2qQdLV") - .unwrap(), - ); - - let sig2 = Sig::Ed25519( - ed25519::Signature::from_base64( - "1eubHHbuNfilHHH0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\ - mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==", - ) - .unwrap(), - ); - - { - let doc = PlainTextDocument { - text, - issuers: vec![issuer1], - signatures: vec![sig1], - }; - - assert_eq!(doc.verify_signatures(), VerificationResult::Valid()); - } - - { - let doc = PlainTextDocument { - text, - issuers: vec![issuer1], - signatures: vec![sig2], - }; - - assert_eq!( - doc.verify_signatures(), - VerificationResult::Invalid(vec![0]) - ); - } - - { - let doc = PlainTextDocument { - text, - issuers: vec![issuer1, issuer2], - signatures: vec![sig1], - }; - - assert_eq!( - doc.verify_signatures(), - VerificationResult::IncompletePairs(2, 1) - ); - } - - { - let doc = PlainTextDocument { - text, - issuers: vec![issuer1], - signatures: vec![sig1, sig2], - }; - - assert_eq!( - doc.verify_signatures(), - VerificationResult::IncompletePairs(1, 2) - ); - } - } -} diff --git a/documents/blockchain/v10/documents/block.rs b/documents/src/v10/block.rs similarity index 96% rename from documents/blockchain/v10/documents/block.rs rename to documents/src/v10/block.rs index 72db06e6797dbf0ae367f04569200456de257148..b03e00f2d642692d654842d49335439292f0ac28 100644 --- a/documents/blockchain/v10/documents/block.rs +++ b/documents/src/v10/block.rs @@ -19,17 +19,16 @@ use crypto::digest::Digest; use crypto::sha2::Sha256; use duniter_crypto::hashs::Hash; use duniter_crypto::keys::*; - -use blockchain::v10::documents::certification::CertificationDocument; -use blockchain::v10::documents::identity::IdentityDocument; -use blockchain::v10::documents::membership::MembershipDocument; -use blockchain::v10::documents::revocation::RevocationDocument; -use blockchain::v10::documents::transaction::TransactionDocument; -use blockchain::v10::documents::*; -use blockchain::{BlockchainProtocol, Document, IntoSpecializedDocument}; use std::ops::Deref; -use CurrencyName; -use {BlockHash, BlockId, Blockstamp}; + +use blockstamp::Blockstamp; +use v10::certification::CertificationDocument; +use v10::identity::IdentityDocument; +use v10::membership::MembershipDocument; +use v10::revocation::RevocationDocument; +use v10::transaction::TransactionDocument; +use v10::*; +use *; #[derive(Debug, Clone)] /// Store error in block parameters parsing @@ -510,10 +509,11 @@ impl IntoSpecializedDocument<BlockchainProtocol> for BlockDocument { #[cfg(test)] mod tests { + use super::certification::CertificationDocumentParser; + use super::transaction::TransactionDocumentParser; use super::*; - use blockchain::v10::documents::V10DocumentParser; - use blockchain::{Document, DocumentParser, VerificationResult}; use std::ops::Deref; + use {Document, VerificationResult}; #[test] fn generate_and_verify_empty_block() { @@ -575,7 +575,7 @@ mod tests { #[test] fn generate_and_verify_block() { - let cert1_ = V10DocumentParser::parse("Version: 10 + let cert1 = CertificationDocumentParser::parse("Version: 10 Type: Certification Currency: g1 Issuer: 6TAzLWuNcSqgNDNpAutrKpPXcGJwy1ZEMeVvZSZNs2e3 @@ -584,13 +584,13 @@ IdtyUniqueID: PascaleM IdtyTimestamp: 97401-0000003821911909F98519CC773D2D3E5CFE3D5DBB39F4F4FF33B96B4D41800E IdtySignature: QncUVXxZ2NfARjdJOn6luILvDuG1NuK9qSoaU4CST2Ij8z7oeVtEgryHl+EXOjSe6XniALsCT0gU8wtadcA/Cw== CertTimestamp: 106669-000003682E6FE38C44433DCE92E8B2A26C69B6D7867A2BAED231E788DDEF4251 -UmseG2XKNwKcY8RFi6gUCT91udGnnNmSh7se10J1jeRVlwf+O2Tyb2Cccot9Dt7BO4+Kx2P6vFJB3oVGGHMxBA==").unwrap(); - let cert1 = match cert1_ { +UmseG2XKNwKcY8RFi6gUCT91udGnnNmSh7se10J1jeRVlwf+O2Tyb2Cccot9Dt7BO4+Kx2P6vFJB3oVGGHMxBA==", "g1").expect("Fail to parse cert1"); + let cert1 = match cert1 { V10Document::Certification(doc) => (*doc.deref()).clone(), _ => panic!("Wrong document type"), }; - let tx1_ = V10DocumentParser::parse("Version: 10 + let tx1 = TransactionDocumentParser::parse("Version: 10 Type: Transaction Currency: g1 Blockstamp: 107982-000001242F6DA51C06A915A96C58BAA37AB3D1EB51F6E1C630C707845ACF764B @@ -604,13 +604,13 @@ Unlocks: 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==").unwrap(); - let tx1 = match tx1_ { +T0LlCcbIn7xDFws48H8LboN6NxxwNXXTovG4PROLf7tkUAueHFWjfwZFKQXeZEHxfaL1eYs3QspGtLWUHPRVCQ==", "g1").expect("Fail to parse tx1"); + let tx1 = match tx1 { V10Document::Transaction(doc) => (*doc.deref()).clone(), _ => panic!("Wrong document type"), }; - let tx2_ = V10DocumentParser::parse("Version: 10 + let tx2 = TransactionDocumentParser::parse("Version: 10 Type: Transaction Currency: g1 Blockstamp: 107982-000001242F6DA51C06A915A96C58BAA37AB3D1EB51F6E1C630C707845ACF764B @@ -624,8 +624,8 @@ Unlocks: 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==").unwrap(); - let tx2 = match tx2_ { +a9PHPuSfw7jW8FRQHXFsGi/bnLjbtDnTYvEVgUC9u0WlR7GVofa+Xb+l5iy6NwuEXiwvueAkf08wPVY8xrNcCg==", "g1").expect("Fail to parse tx2"); + let tx2 = match tx2 { V10Document::Transaction(doc) => (*doc.deref()).clone(), _ => panic!("Wrong document type"), }; diff --git a/documents/blockchain/v10/documents/certification.rs b/documents/src/v10/certification.rs similarity index 67% rename from documents/blockchain/v10/documents/certification.rs rename to documents/src/v10/certification.rs index e03213f00917646239df20f8d8270860efa8c172..00ec4df88f087ec61f53eeda31862ac2d570fd84 100644 --- a/documents/blockchain/v10/documents/certification.rs +++ b/documents/src/v10/certification.rs @@ -16,18 +16,11 @@ //! Wrappers around Certification documents. use duniter_crypto::keys::*; -use regex::Regex; +use pest::Parser; -use blockchain::v10::documents::*; -use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument}; -use BlockId; -use Blockstamp; - -lazy_static! { - static ref CERTIFICATION_REGEX: Regex = Regex::new( - "^Issuer: (?P<issuer>[1-9A-Za-z]{43,44})\nIdtyIssuer: (?P<target>[1-9A-Za-z]{43,44})\nIdtyUniqueID: (?P<idty_uid>[[:alnum:]_-]+)\nIdtyTimestamp: (?P<idty_blockstamp>[0-9]+-[0-9A-F]{64})\nIdtySignature: (?P<idty_sig>(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?)\nCertTimestamp: (?P<blockstamp>[0-9]+-[0-9A-F]{64})\n$" - ).unwrap(); -} +use blockstamp::Blockstamp; +use v10::*; +use *; #[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] /// Wrap an Compact Revocation document (in block content) @@ -124,7 +117,7 @@ impl Document for CertificationDocument { } fn as_bytes(&self) -> &[u8] { - self.as_text().as_bytes() + self.as_text_without_signature().as_bytes() } } @@ -228,47 +221,74 @@ CertTimestamp: {blockstamp} #[derive(Debug, Clone, Copy)] pub struct CertificationDocumentParser; -impl StandardTextDocumentParser for CertificationDocumentParser { - fn parse_standard( - doc: &str, - body: &str, - currency: &str, - signatures: Vec<Sig>, - ) -> Result<V10Document, V10DocumentParsingError> { - if let Some(caps) = CERTIFICATION_REGEX.captures(body) { - let issuer = &caps["issuer"]; - let target = &caps["target"]; - let identity_username = &caps["idty_uid"]; - let identity_blockstamp = &caps["idty_blockstamp"]; - let identity_sig = &caps["idty_sig"]; - let blockstamp = &caps["blockstamp"]; - - // Regex match so should not fail. - // TODO : Test it anyway - let issuer = PubKey::Ed25519(ed25519::PublicKey::from_base58(issuer).unwrap()); - let target = PubKey::Ed25519(ed25519::PublicKey::from_base58(target).unwrap()); - let identity_username = String::from(identity_username); - let identity_blockstamp = Blockstamp::from_string(identity_blockstamp).unwrap(); - let identity_sig = Sig::Ed25519(ed25519::Signature::from_base64(identity_sig).unwrap()); - let blockstamp = Blockstamp::from_string(blockstamp).unwrap(); - - Ok(V10Document::Certification(Box::new( - CertificationDocument { - text: doc.to_owned(), - issuers: vec![issuer], - currency: currency.to_owned(), - target, - identity_username, - identity_blockstamp, - identity_sig, - blockstamp, - signatures, - }, - ))) - } else { - Err(V10DocumentParsingError::InvalidInnerFormat( - "Certification".to_string(), - )) +impl TextDocumentParser for CertificationDocumentParser { + fn parse(doc: &str, currency: &str) -> Result<V10Document, V10DocumentParsingError> { + match DocumentsParser::parse(Rule::cert, doc) { + Ok(mut doc_ast) => { + let cert_ast = doc_ast.next().unwrap(); // get and unwrap the `cert` rule; never fails + let cert_vx_ast = cert_ast.into_inner().next().unwrap(); // get and unwrap the `cert_vX` rule; never fails + + match cert_vx_ast.as_rule() { + Rule::cert_v10 => { + let mut pubkeys = Vec::with_capacity(2); + let mut uid = ""; + let mut sigs = Vec::with_capacity(2); + let mut blockstamps = Vec::with_capacity(2); + for field in cert_vx_ast.into_inner() { + match field.as_rule() { + Rule::currency => { + if currency != field.as_str() { + return Err(V10DocumentParsingError::InvalidCurrency()); + } + } + Rule::pubkey => pubkeys.push(PubKey::Ed25519( + ed25519::PublicKey::from_base58(field.as_str()).unwrap(), // Grammar ensures that we have a base58 string. + )), + Rule::uid => { + uid = field.as_str(); + } + Rule::blockstamp => { + if blockstamps.len() > 1 { + return Err(V10DocumentParsingError::InvalidInnerFormat( + "Cert document must contain exactly two blockstamps !", + )); + } + let mut inner_rules = field.into_inner(); // { integer ~ "-" ~ hash } + + let block_id: &str = inner_rules.next().unwrap().as_str(); + let block_hash: &str = inner_rules.next().unwrap().as_str(); + blockstamps.push(Blockstamp { + id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string. + hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string. + }); + } + Rule::ed25519_sig => { + sigs.push(Sig::Ed25519( + ed25519::Signature::from_base64(field.as_str()).unwrap(), // Grammar ensures that we have a base64 string. + )); + } + Rule::EOI => (), + _ => panic!("unexpected rule"), // Grammar ensures that we never reach this line + } + } + Ok(V10Document::Certification(Box::new( + CertificationDocument { + text: doc.to_owned(), + issuers: vec![pubkeys[0]], + currency: currency.to_owned(), + target: pubkeys[1], + identity_username: uid.to_owned(), + identity_blockstamp: blockstamps[0], + identity_sig: sigs[0], + blockstamp: blockstamps[1], + signatures: vec![sigs[1]], + }, + ))) + } + _ => Err(V10DocumentParsingError::UnexpectedVersion()), + } + } + Err(pest_error) => panic!("{}", pest_error), //Err(V10DocumentParsingError::PestError()), } } } @@ -276,8 +296,8 @@ impl StandardTextDocumentParser for CertificationDocumentParser { #[cfg(test)] mod tests { use super::*; - use blockchain::VerificationResult; use duniter_crypto::keys::{PrivateKey, PublicKey, Signature}; + use VerificationResult; #[test] fn generate_real_document() { @@ -334,19 +354,6 @@ mod tests { ); } - #[test] - fn certification_standard_regex() { - assert!(CERTIFICATION_REGEX.is_match( - "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV -IdtyIssuer: 7jzkd8GiFnpys4X7mP78w2Y3y3kwdK6fVSLEaojd3aH9 -IdtyUniqueID: fbarbut -IdtyTimestamp: 98221-000000575AC04F5164F7A307CDB766139EA47DD249E4A2444F292BC8AAB408B3 -IdtySignature: DjeipIeb/RF0tpVCnVnuw6mH1iLJHIsDfPGLR90Twy3PeoaDz6Yzhc/UjLWqHCi5Y6wYajV0dNg4jQRUneVBCQ== -CertTimestamp: 99956-00000472758331FDA8388E30E50CA04736CBFD3B7C21F34E74707107794B56DD -" - )); - } - #[test] fn certification_document() { let doc = "Version: 10 @@ -358,24 +365,11 @@ IdtyUniqueID: mmpio IdtyTimestamp: 7543-000044410C5370DE8DBA911A358F318096B7A269CFC2BB93272E397CC513EA0A IdtySignature: SmSweUD4lEMwiZfY8ux9maBjrQQDkC85oMNsin6oSQCPdXG8sFCZ4FisUaWqKsfOlZVb/HNa+TKzD2t0Yte+DA== CertTimestamp: 167884-0001DFCA28002A8C96575E53B8CEF8317453A7B0BA255542CCF0EC8AB5E99038 -"; - - let body = "Issuer: 5B8iMAzq1dNmFe3ZxFTBQkqhq4fsztg1gZvxHXCk1XYH -IdtyIssuer: mMPioknj2MQCX9KyKykdw8qMRxYR2w1u3UpdiEJHgXg -IdtyUniqueID: mmpio -IdtyTimestamp: 7543-000044410C5370DE8DBA911A358F318096B7A269CFC2BB93272E397CC513EA0A -IdtySignature: SmSweUD4lEMwiZfY8ux9maBjrQQDkC85oMNsin6oSQCPdXG8sFCZ4FisUaWqKsfOlZVb/HNa+TKzD2t0Yte+DA== -CertTimestamp: 167884-0001DFCA28002A8C96575E53B8CEF8317453A7B0BA255542CCF0EC8AB5E99038 -"; +wqZxPEGxLrHGv8VdEIfUGvUcf+tDdNTMXjLzVRCQ4UhlhDRahOMjfcbP7byNYr5OfIl83S1MBxF7VJgu8YasCA=="; let currency = "g1-test"; - let signatures = vec![Sig::Ed25519(ed25519::Signature::from_base64( -"wqZxPEGxLrHGv8VdEIfUGvUcf+tDdNTMXjLzVRCQ4UhlhDRahOMjfcbP7byNYr5OfIl83S1MBxF7VJgu8YasCA==" - ).unwrap())]; - - let doc = - CertificationDocumentParser::parse_standard(doc, body, currency, signatures).unwrap(); + let doc = CertificationDocumentParser::parse(doc, currency).unwrap(); if let V10Document::Certification(doc) = doc { println!("Doc : {:?}", doc); assert_eq!(doc.verify_signatures(), VerificationResult::Valid()); diff --git a/documents/blockchain/v10/documents/identity.rs b/documents/src/v10/identity.rs similarity index 67% rename from documents/blockchain/v10/documents/identity.rs rename to documents/src/v10/identity.rs index 4eacf71e517e38cf909d46a1c5ccc4ef4a621dfc..fb228f5f65974f34712cab73a9482b6b50313495 100644 --- a/documents/blockchain/v10/documents/identity.rs +++ b/documents/src/v10/identity.rs @@ -15,16 +15,11 @@ //! Wrappers around Identity documents. -use blockchain::v10::documents::*; -use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument}; -use regex::Regex; -use Blockstamp; +use pest::Parser; -lazy_static! { - static ref IDENTITY_REGEX: Regex = Regex::new( - "^Issuer: (?P<issuer>[1-9A-Za-z][^OIl]{43,44})\nUniqueID: (?P<uid>[[:alnum:]_-]+)\nTimestamp: (?P<blockstamp>[0-9]+-[0-9A-F]{64})\n$" - ).unwrap(); -} +use v10::*; +use Blockstamp; +use *; /// Wrap an Identity document. /// @@ -86,7 +81,7 @@ impl Document for IdentityDocument { } fn as_bytes(&self) -> &[u8] { - self.as_text().as_bytes() + self.as_text_without_signature().as_bytes() } } @@ -204,35 +199,60 @@ Timestamp: {blockstamp} #[derive(Debug, Clone, Copy)] pub struct IdentityDocumentParser; -impl StandardTextDocumentParser for IdentityDocumentParser { - fn parse_standard( - doc: &str, - body: &str, - currency: &str, - signatures: Vec<Sig>, - ) -> Result<V10Document, V10DocumentParsingError> { - if let Some(caps) = IDENTITY_REGEX.captures(body) { - let issuer = &caps["issuer"]; - let uid = &caps["uid"]; - let blockstamp = &caps["blockstamp"]; - - // Regex match so should not fail. - // TODO : Test it anyway - let issuer = PubKey::Ed25519(ed25519::PublicKey::from_base58(issuer).unwrap()); - let blockstamp = Blockstamp::from_string(blockstamp).unwrap(); - - Ok(V10Document::Identity(IdentityDocument { - text: Some(doc.to_owned()), - currency: currency.to_owned(), - username: uid.to_owned(), - blockstamp, - issuers: vec![issuer], - signatures, - })) - } else { - Err(V10DocumentParsingError::InvalidInnerFormat( - "Identity".to_string(), - )) +impl TextDocumentParser for IdentityDocumentParser { + fn parse(doc: &str, currency: &str) -> Result<V10Document, V10DocumentParsingError> { + match DocumentsParser::parse(Rule::idty, doc) { + Ok(mut doc_ast) => { + let idty_ast = doc_ast.next().unwrap(); // get and unwrap the `idty` rule; never fails + let idty_vx_ast = idty_ast.into_inner().next().unwrap(); // get and unwrap the `idty_vX` rule; never fails + + match idty_vx_ast.as_rule() { + Rule::idty_v10 => { + let mut pubkey_str = ""; + let mut uid = ""; + let mut blockstamp = Blockstamp::default(); + let mut sig_str = ""; + for field in idty_vx_ast.into_inner() { + match field.as_rule() { + Rule::currency => { + if currency != field.as_str() { + return Err(V10DocumentParsingError::InvalidCurrency()); + } + } + Rule::pubkey => pubkey_str = field.as_str(), + Rule::uid => uid = field.as_str(), + Rule::blockstamp => { + let mut inner_rules = field.into_inner(); // { integer ~ "-" ~ hash } + + let block_id: &str = inner_rules.next().unwrap().as_str(); + let block_hash: &str = inner_rules.next().unwrap().as_str(); + blockstamp = Blockstamp { + id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string. + hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string. + }; + } + Rule::ed25519_sig => sig_str = field.as_str(), + Rule::EOI => (), + _ => panic!("unexpected rule"), // Grammar ensures that we never reach this line + } + } + Ok(V10Document::Identity(IdentityDocument { + text: Some(doc.to_owned()), + currency: currency.to_owned(), + username: uid.to_owned(), + blockstamp, + issuers: vec![PubKey::Ed25519( + ed25519::PublicKey::from_base58(pubkey_str).unwrap(), + )], // Grammar ensures that we have a base58 string. + signatures: vec![Sig::Ed25519( + ed25519::Signature::from_base64(sig_str).unwrap(), + )], // Grammar ensures that we have a base64 string. + })) + } + _ => Err(V10DocumentParsingError::UnexpectedVersion()), + } + } + Err(pest_error) => panic!("{}", pest_error), //Err(V10DocumentParsingError::PestError()), } } } @@ -240,8 +260,8 @@ impl StandardTextDocumentParser for IdentityDocumentParser { #[cfg(test)] mod tests { use super::*; - use blockchain::{Document, VerificationResult}; use duniter_crypto::keys::{PrivateKey, PublicKey, Signature}; + use {Document, VerificationResult}; #[test] fn generate_real_document() { @@ -288,16 +308,6 @@ mod tests { ); } - #[test] - fn identity_standard_regex() { - assert!(IDENTITY_REGEX.is_match( - "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV -UniqueID: tic -Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -" - )); - } - #[test] fn parse_identity_document() { let doc = "Version: 10 @@ -306,20 +316,11 @@ Currency: duniter_unit_test_currency Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV UniqueID: tic Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -"; - - let body = "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV -UniqueID: tic -Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -"; +1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg=="; let currency = "duniter_unit_test_currency"; - let signatures = vec![Sig::Ed25519(ed25519::Signature::from_base64( -"1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==" - ).unwrap())]; - - let doc = IdentityDocumentParser::parse_standard(doc, body, currency, signatures).unwrap(); + let doc = IdentityDocumentParser::parse(doc, currency).expect("Fail to parse idty doc !"); if let V10Document::Identity(doc) = doc { println!("Doc : {:?}", doc); assert_eq!(doc.verify_signatures(), VerificationResult::Valid()) diff --git a/documents/blockchain/v10/documents/membership.rs b/documents/src/v10/membership.rs similarity index 69% rename from documents/blockchain/v10/documents/membership.rs rename to documents/src/v10/membership.rs index 3e3fb554a114a3b3bca72af5167c073e4795680a..55eb6e4606ff7a37fa41fcad35ca087a3e45e1ab 100644 --- a/documents/blockchain/v10/documents/membership.rs +++ b/documents/src/v10/membership.rs @@ -16,22 +16,11 @@ //! Wrappers around Membership documents. use duniter_crypto::keys::*; -use regex::Regex; - -use blockchain::v10::documents::*; -use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument}; -use Blockstamp; - -lazy_static! { - static ref MEMBERSHIP_REGEX: Regex = Regex::new( - "^Issuer: (?P<issuer>[1-9A-Za-z][^OIl]{43,44})\n\ - Block: (?P<blockstamp>[0-9]+-[0-9A-F]{64})\n\ - Membership: (?P<membership>(IN|OUT))\n\ - UserID: (?P<ity_user>[[:alnum:]_-]+)\n\ - CertTS: (?P<ity_block>[0-9]+-[0-9A-F]{64})\n$" - ) - .unwrap(); -} +use pest::Parser; + +use blockstamp::Blockstamp; +use v10::*; +use *; /// Type of a Membership. #[derive(Debug, Deserialize, Clone, Copy, Hash, Serialize, PartialEq, Eq)] @@ -136,7 +125,7 @@ impl Document for MembershipDocument { } fn as_bytes(&self) -> &[u8] { - self.as_text().as_bytes() + self.as_text_without_signature().as_bytes() } } @@ -259,47 +248,68 @@ CertTS: {ity_blockstamp} #[derive(Debug, Clone, Copy)] pub struct MembershipDocumentParser; -impl StandardTextDocumentParser for MembershipDocumentParser { - fn parse_standard( - doc: &str, - body: &str, - currency: &str, - signatures: Vec<Sig>, - ) -> Result<V10Document, V10DocumentParsingError> { - if let Some(caps) = MEMBERSHIP_REGEX.captures(body) { - let issuer = &caps["issuer"]; - - let blockstamp = &caps["blockstamp"]; - let membership = &caps["membership"]; - let username = &caps["ity_user"]; - let ity_block = &caps["ity_block"]; - - // Regex match so should not fail. - // TODO : Test it anyway - let issuer = PubKey::Ed25519(ed25519::PublicKey::from_base58(issuer).unwrap()); - let blockstamp = Blockstamp::from_string(blockstamp).unwrap(); - let membership = match membership { - "IN" => MembershipType::In(), - "OUT" => MembershipType::Out(), - _ => panic!("Invalid membership type {}", membership), - }; - - let ity_block = Blockstamp::from_string(ity_block).unwrap(); - - Ok(V10Document::Membership(MembershipDocument { - text: Some(doc.to_owned()), - issuers: vec![issuer], - currency: currency.to_owned(), - blockstamp, - membership, - identity_username: username.to_owned(), - identity_blockstamp: ity_block, - signatures, - })) - } else { - Err(V10DocumentParsingError::InvalidInnerFormat( - "Membership".to_string(), - )) +impl TextDocumentParser for MembershipDocumentParser { + fn parse(doc: &str, currency: &str) -> Result<V10Document, V10DocumentParsingError> { + match DocumentsParser::parse(Rule::membership, doc) { + Ok(mut doc_ast) => { + let membership_ast = doc_ast.next().unwrap(); // get and unwrap the `membership` rule; never fails + let membership_vx_ast = membership_ast.into_inner().next().unwrap(); // get and unwrap the `membership_vX` rule; never fails + + match membership_vx_ast.as_rule() { + Rule::membership_v10 => { + let mut pubkey_str = ""; + let mut uid = ""; + let mut blockstamps = Vec::with_capacity(2); + let mut membership = MembershipType::In(); + let mut sig_str = ""; + for field in membership_vx_ast.into_inner() { + match field.as_rule() { + Rule::currency => { + if currency != field.as_str() { + return Err(V10DocumentParsingError::InvalidCurrency()); + } + } + Rule::pubkey => pubkey_str = field.as_str(), + Rule::uid => uid = field.as_str(), + Rule::membership_in => membership = MembershipType::In(), + Rule::membership_out => membership = MembershipType::Out(), + Rule::blockstamp => { + if blockstamps.len() > 1 { + return Err(V10DocumentParsingError::InvalidInnerFormat("Membership document must have exactly two blockstamps !")); + } + let mut inner_rules = field.into_inner(); // { integer ~ "-" ~ hash } + + let block_id: &str = inner_rules.next().unwrap().as_str(); + let block_hash: &str = inner_rules.next().unwrap().as_str(); + blockstamps.push(Blockstamp { + id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string. + hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string. + }); + } + Rule::ed25519_sig => sig_str = field.as_str(), + Rule::EOI => (), + _ => panic!("unexpected rule"), // Grammar ensures that we never reach this line + } + } + Ok(V10Document::Membership(MembershipDocument { + text: Some(doc.to_owned()), + issuers: vec![PubKey::Ed25519( + ed25519::PublicKey::from_base58(pubkey_str).unwrap(), + )], // Grammar ensures that we have a base58 string. + currency: currency.to_owned(), + blockstamp: blockstamps[0], + membership, + identity_username: uid.to_owned(), + identity_blockstamp: blockstamps[1], + signatures: vec![Sig::Ed25519( + ed25519::Signature::from_base64(sig_str).unwrap(), + )], // Grammar ensures that we have a base64 string. + })) + } + _ => Err(V10DocumentParsingError::UnexpectedVersion()), + } + } + Err(pest_error) => panic!("{}", pest_error), //Err(V10DocumentParsingError::PestError()), } } } @@ -307,8 +317,8 @@ impl StandardTextDocumentParser for MembershipDocumentParser { #[cfg(test)] mod tests { use super::*; - use blockchain::VerificationResult; use duniter_crypto::keys::{PrivateKey, PublicKey, Signature}; + use VerificationResult; #[test] fn generate_real_document() { @@ -357,18 +367,6 @@ mod tests { ); } - #[test] - fn membership_standard_regex() { - assert!(MEMBERSHIP_REGEX.is_match( - "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV -Block: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -Membership: IN -UserID: tic -CertTS: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -" - )); - } - #[test] fn membership_identity_document() { let doc = "Version: 10 @@ -379,23 +377,11 @@ Block: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 Membership: IN UserID: tic CertTS: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -"; - - let body = "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV -Block: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -Membership: IN -UserID: tic -CertTS: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -"; +s2hUbokkibTAWGEwErw6hyXSWlWFQ2UWs2PWx8d/kkElAyuuWaQq4Tsonuweh1xn4AC1TVWt4yMR3WrDdkhnAw=="; let currency = "duniter_unit_test_currency"; - let signatures = vec![Sig::Ed25519(ed25519::Signature::from_base64( -"s2hUbokkibTAWGEwErw6hyXSWlWFQ2UWs2PWx8d/kkElAyuuWaQq4Tsonuweh1xn4AC1TVWt4yMR3WrDdkhnAw==" - ).unwrap())]; - - let doc = - MembershipDocumentParser::parse_standard(doc, body, currency, signatures).unwrap(); + let doc = MembershipDocumentParser::parse(doc, currency).unwrap(); if let V10Document::Membership(doc) = doc { println!("Doc : {:?}", doc); assert_eq!(doc.verify_signatures(), VerificationResult::Valid()); diff --git a/documents/blockchain/v10/documents/mod.rs b/documents/src/v10/mod.rs similarity index 59% rename from documents/blockchain/v10/documents/mod.rs rename to documents/src/v10/mod.rs index 3e3d2137834cf3b39e400e49c0858e4b84306538..0cefad227a7d6a59f717ae1cecbac6b9721997dc 100644 --- a/documents/blockchain/v10/documents/mod.rs +++ b/documents/src/v10/mod.rs @@ -15,12 +15,6 @@ //! Provide wrappers around Duniter blockchain documents for protocol version 10. -use blockchain::v10::documents::identity::IdentityDocumentParser; -use blockchain::{Document, DocumentBuilder, DocumentParser}; -use crypto::digest::Digest; -use duniter_crypto::keys::*; -use regex::Regex; - pub mod block; pub mod certification; pub mod identity; @@ -28,31 +22,16 @@ pub mod membership; pub mod revocation; pub mod transaction; -pub use blockchain::v10::documents::block::BlockDocument; -pub use blockchain::v10::documents::certification::{ - CertificationDocument, CertificationDocumentParser, -}; -pub use blockchain::v10::documents::identity::{IdentityDocument, IdentityDocumentBuilder}; -pub use blockchain::v10::documents::membership::{MembershipDocument, MembershipDocumentParser}; -pub use blockchain::v10::documents::revocation::{RevocationDocument, RevocationDocumentParser}; -pub use blockchain::v10::documents::transaction::{ - TransactionDocument, TransactionDocumentBuilder, TransactionDocumentParser, -}; - -use std::marker::Sized; - -// Use of lazy_static so the regex is only compiled at first use. -lazy_static! { - static ref DOCUMENT_REGEX: Regex = Regex::new( - "^(?P<doc>Version: (?P<version>[0-9]+)\n\ - Type: (?P<type>[[:alpha:]]+)\n\ - Currency: (?P<currency>[[:alnum:] _-]+)\n\ - (?P<body>(?:.*\n)+?))\ - (?P<sigs>([[:alnum:]+/=]+\n)*([[:alnum:]+/=]+))$" - ) - .unwrap(); - static ref SIGNATURES_REGEX: Regex = Regex::new("[[:alnum:]+/=]+\n?").unwrap(); -} +use crypto::digest::Digest; +use duniter_crypto::keys::PrivateKey; + +pub use v10::block::BlockDocument; +use v10::certification::*; +use v10::identity::*; +use v10::membership::*; +use v10::revocation::*; +use v10::transaction::*; +use *; #[derive(Clone, Debug, Deserialize, Serialize)] /// Contains a document in full or compact format @@ -124,22 +103,34 @@ pub trait TextDocument: Document<PublicKey = PubKey, CurrencyType = str> { /// Return document as text. fn as_text(&self) -> &str; + /// Return document as text without signature. + fn as_text_without_signature(&self) -> &str { + let text = self.as_text(); + let mut lines: Vec<&str> = self.as_text().split('\n').collect(); + let sigs = self.signatures(); + let mut sigs_str_len = sigs.len() - 1; + for _ in sigs { + sigs_str_len += lines.pop().unwrap_or("").len(); + } + &text[0..(text.len() - sigs_str_len)] + } + /// Return sha256 hash of text document fn hash<H: Digest>(&self, digest: &mut H) -> String { digest.input_str(self.as_text()); digest.result_str() } - /// Return document as text with leading signatures. + /*/// Return document as text with leading signatures. fn as_text_with_signatures(&self) -> String { let mut text = self.as_text().to_string(); - + for sig in self.signatures() { text = format!("{}{}\n", text, sig.to_base64()); } - + text - } + }*/ /// Generate compact document. /// the compact format is the one used in the blocks. @@ -191,9 +182,15 @@ pub enum V10DocumentParsingError { /// The given source don't have a valid document format. InvalidWrapperFormat(), /// The given source don't have a valid specific document format (document type). - InvalidInnerFormat(String), + InvalidInnerFormat(&'static str), /// Type fields contains an unknown document type. UnknownDocumentType(String), + /// Error with pest parser + PestError(), + /// Invalid currency + InvalidCurrency(), + /// UnexpectedVersion + UnexpectedVersion(), } /// V10 Documents in separated parts @@ -209,134 +206,186 @@ pub struct V10DocumentParts { pub signatures: Vec<Sig>, } -trait StandardTextDocumentParser { - fn parse_standard( - doc: &str, - body: &str, - currency: &str, - signatures: Vec<Sig>, - ) -> Result<V10Document, V10DocumentParsingError>; +trait TextDocumentParser { + fn parse(doc: &str, currency: &str) -> Result<V10Document, V10DocumentParsingError>; } -/// A V10 document parser. +/*/// A V10 document parser. #[derive(Debug, Clone, Copy)] pub struct V10DocumentParser; impl<'a> DocumentParser<&'a str, V10Document, V10DocumentParsingError> for V10DocumentParser { fn parse(source: &'a str) -> Result<V10Document, V10DocumentParsingError> { - if let Some(caps) = DOCUMENT_REGEX.captures(source) { - let doctype = &caps["type"]; - let doc = &caps["doc"]; - let currency = &caps["currency"]; - let body = &caps["body"]; - let sigs = SIGNATURES_REGEX - .captures_iter(&caps["sigs"]) - .map(|capture| Sig::Ed25519(ed25519::Signature::from_base64(&capture[0]).unwrap())) - .collect::<Vec<_>>(); - - // TODO : Improve error handling of Signature::from_base64 failure - - match doctype { - "Identity" => IdentityDocumentParser::parse_standard(doc, body, currency, sigs), - "Membership" => MembershipDocumentParser::parse_standard(doc, body, currency, sigs), - "Certification" => { - CertificationDocumentParser::parse_standard(doc, body, currency, sigs) - } - "Revocation" => RevocationDocumentParser::parse_standard(doc, body, currency, sigs), - "Transaction" => { - TransactionDocumentParser::parse_standard(doc, body, currency, sigs) + /*match DocumentsParser::parse(Rule::document_v10, source) { + Ok(mut source_ast) => { + let doc_v10_ast = source_ast.next().unwrap(); // get and unwrap the `document_v10` rule; never fails + let doc_type_v10_ast = doc_v10_ast.into_inner().next().unwrap(); // get and unwrap the `{DOC_TYPE}_v10` rule; never fails + + match doc_type_v10_ast.as_rule() { + Rule::idty_v10 => IdentityDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]), + Rule::membership_v10 => MembershipDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]), + Rule::cert_v10 => CertificationDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]), + Rule::revoc_v10 => RevocationDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]), + Rule::tx_v10 => TransactionDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]), } - _ => Err(V10DocumentParsingError::UnknownDocumentType( - doctype.to_string(), - )), } - } else { - Err(V10DocumentParsingError::InvalidWrapperFormat()) - } - } + Err(_) => Err(V10DocumentParsingError::InvalidWrapperFormat()), + }*/ +if let Some(caps) = DOCUMENT_REGEX.captures(source) { +let doctype = &caps["type"]; +let currency = &caps["currency"]; + +// TODO : Improve error handling of Signature::from_base64 failure + +match doctype { +"Identity" => IdentityDocumentParser::parse_standard(source, currency), +"Membership" => MembershipDocumentParser::parse_standard(source, currency), +"Certification" => CertificationDocumentParser::parse_standard(source, currency), +"Revocation" => RevocationDocumentParser::parse_standard(source, currency), +"Transaction" => TransactionDocumentParser::parse_standard(source, currency), +_ => Err(V10DocumentParsingError::UnknownDocumentType( +doctype.to_string(), +)), } +} else { +Err(V10DocumentParsingError::InvalidWrapperFormat()) +} +} +}*/ #[cfg(test)] mod tests { + use super::certification::CertificationDocumentParser; + use super::identity::IdentityDocumentParser; + use super::membership::MembershipDocumentParser; + use super::revocation::RevocationDocumentParser; + use super::transaction::TransactionDocumentParser; use super::*; - use blockchain::{Document, VerificationResult}; + use duniter_crypto::keys::*; + + // simple text document for signature testing + #[derive(Debug, Clone)] + struct PlainTextDocument { + pub text: &'static str, + pub issuers: Vec<PubKey>, + pub signatures: Vec<Sig>, + } - #[test] - fn document_regex() { - assert!(DOCUMENT_REGEX.is_match( - "Version: 10 -Type: Transaction -Currency: beta_brousouf -Blockstamp: 204-00003E2B8A35370BA5A7064598F628A62D4E9EC1936BE8651CE9A85F2E06981B -Locktime: 0 -Issuers: -HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY -CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp -9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB -Inputs: -40:2:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2 -70:2:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8 -20:2:D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:46 -70:2:T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3 -20:2:T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5 -15:2:D:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:46 -Unlocks: -0:SIG(0) -1:XHX(7665798292) -2:SIG(0) -3:SIG(0) SIG(2) -4:SIG(0) SIG(1) SIG(2) -5:SIG(2) -Outputs: -120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g) -146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx) -49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i)\ - || XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85)) -Comment: -----@@@----- (why not this comment?) -42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r -2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX -2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk" - )); - - assert!(DOCUMENT_REGEX.is_match( - "Version: 10 -Type: Certification -Currency: beta_brousouf -Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV -IdtyIssuer: HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd -IdtyUniqueID: lolcat -IdtyTimestamp: 32-DB30D958EE5CB75186972286ED3F4686B8A1C2CD -IdtySignature: J3G9oM5AKYZNLAB5Wx499w61NuUoS57JVccTShUb\ -GpCMjCqj9yXXqNq7dyZpDWA6BxipsiaMZhujMeBfCznzyci -CertTimestamp: 36-1076F10A7397715D2BEE82579861999EA1F274AC -SoKwoa8PFfCDJWZ6dNCv7XstezHcc2BbKiJgVDXv82R5zYR83nis9dShLgWJ5w48noVUHimdngzYQneNYSMV3rk" - )); + impl Document for PlainTextDocument { + type PublicKey = PubKey; + type CurrencyType = str; + + fn version(&self) -> u16 { + unimplemented!() + } + + fn currency(&self) -> &str { + unimplemented!() + } + + fn blockstamp(&self) -> Blockstamp { + unimplemented!() + } + + fn issuers(&self) -> &Vec<PubKey> { + &self.issuers + } + + fn signatures(&self) -> &Vec<Sig> { + &self.signatures + } + + fn as_bytes(&self) -> &[u8] { + self.text.as_bytes() + } } #[test] - fn signatures_regex() { - assert_eq!( - SIGNATURES_REGEX - .captures_iter( - " -42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r -2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX -2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk" - ) - .count(), - 3 + fn verify_signatures() { + let text = "Version: 10 +Type: Identity +Currency: duniter_unit_test_currency +Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV +UniqueID: tic +Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 +"; + + // good pair + let issuer1 = PubKey::Ed25519( + ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV") + .unwrap(), + ); + + let sig1 = Sig::Ed25519( + ed25519::Signature::from_base64( + "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\ + mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==", + ) + .unwrap(), ); - assert_eq!( - SIGNATURES_REGEX - .captures_iter( - " -42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r -2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk" - ) - .count(), - 2 + // incorrect pair + let issuer2 = PubKey::Ed25519( + ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt32bzHbA3NJR46DeQYCS2qQdLV") + .unwrap(), ); + + let sig2 = Sig::Ed25519( + ed25519::Signature::from_base64( + "1eubHHbuNfilHHH0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\ + mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==", + ) + .unwrap(), + ); + + { + let doc = PlainTextDocument { + text, + issuers: vec![issuer1], + signatures: vec![sig1], + }; + + assert_eq!(doc.verify_signatures(), VerificationResult::Valid()); + } + + { + let doc = PlainTextDocument { + text, + issuers: vec![issuer1], + signatures: vec![sig2], + }; + + assert_eq!( + doc.verify_signatures(), + VerificationResult::Invalid(vec![0]) + ); + } + + { + let doc = PlainTextDocument { + text, + issuers: vec![issuer1, issuer2], + signatures: vec![sig1], + }; + + assert_eq!( + doc.verify_signatures(), + VerificationResult::IncompletePairs(2, 1) + ); + } + + { + let doc = PlainTextDocument { + text, + issuers: vec![issuer1], + signatures: vec![sig1, sig2], + }; + + assert_eq!( + doc.verify_signatures(), + VerificationResult::IncompletePairs(1, 2) + ); + } } #[test] @@ -349,7 +398,7 @@ UniqueID: elois Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 Ydnclvw76/JHcKSmU9kl9Ie0ne5/X8NYOqPqbGnufIK3eEPRYYdEYaQh+zffuFhbtIRjv6m/DkVLH5cLy/IyAg=="; - let doc = V10DocumentParser::parse(text).unwrap(); + let doc = IdentityDocumentParser::parse(text, "g1").unwrap(); if let V10Document::Identity(doc) = doc { println!("Doc : {:?}", doc); assert_eq!(doc.verify_signatures(), VerificationResult::Valid()) @@ -370,7 +419,7 @@ UserID: elois CertTS: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 FFeyrvYio9uYwY5aMcDGswZPNjGLrl8THn9l3EPKSNySD3SDSHjCljSfFEwb87sroyzJQoVzPwER0sW/cbZMDg=="; - let doc = V10DocumentParser::parse(text).unwrap(); + let doc = MembershipDocumentParser::parse(text, "g1").unwrap(); if let V10Document::Membership(doc) = doc { println!("Doc : {:?}", doc); assert_eq!(doc.verify_signatures(), VerificationResult::Valid()) @@ -392,7 +441,7 @@ IdtySignature: DjeipIeb/RF0tpVCnVnuw6mH1iLJHIsDfPGLR90Twy3PeoaDz6Yzhc/UjLWqHCi5Y CertTimestamp: 99956-00000472758331FDA8388E30E50CA04736CBFD3B7C21F34E74707107794B56DD Hkps1QU4HxIcNXKT8YmprYTVByBhPP1U2tIM7Z8wENzLKIWAvQClkAvBE7pW9dnVa18sJIJhVZUcRrPAZfmjBA=="; - let doc = V10DocumentParser::parse(text).unwrap(); + let doc = CertificationDocumentParser::parse(text, "g1").unwrap(); if let V10Document::Certification(doc) = doc { println!("Doc : {:?}", doc); assert_eq!(doc.verify_signatures(), VerificationResult::Valid()) @@ -412,7 +461,7 @@ IdtyTimestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B85 IdtySignature: 1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg== XXOgI++6qpY9O31ml/FcfbXCE6aixIrgkT5jL7kBle3YOMr+8wrp7Rt+z9hDVjrNfYX2gpeJsuMNfG4T/fzVDQ=="; - let doc = V10DocumentParser::parse(text).unwrap(); + let doc = RevocationDocumentParser::parse(text, "g1").unwrap(); if let V10Document::Revocation(doc) = doc { println!("Doc : {:?}", doc); assert_eq!(doc.verify_signatures(), VerificationResult::Valid()) @@ -441,7 +490,7 @@ Outputs: Comment: c est pour 2 mois d adhesion ressourcerie lnpuFsIymgz7qhKF/GsZ3n3W8ZauAAfWmT4W0iJQBLKJK2GFkesLWeMj/+GBfjD6kdkjreg9M6VfkwIZH+hCCQ=="; - let doc = V10DocumentParser::parse(text).unwrap(); + let doc = TransactionDocumentParser::parse(text, "g1").unwrap(); if let V10Document::Transaction(doc) = doc { println!("Doc : {:?}", doc); assert_eq!(doc.verify_signatures(), VerificationResult::Valid()) diff --git a/documents/blockchain/v10/documents/revocation.rs b/documents/src/v10/revocation.rs similarity index 63% rename from documents/blockchain/v10/documents/revocation.rs rename to documents/src/v10/revocation.rs index 2b059615dd288fe146d215be1dfb0bbe1382554c..d4ca1983cd9918576f982d9f82201ac168d52dcd 100644 --- a/documents/blockchain/v10/documents/revocation.rs +++ b/documents/src/v10/revocation.rs @@ -16,20 +16,11 @@ //! Wrappers around Revocation documents. use duniter_crypto::keys::*; -use regex::Regex; - -use blockchain::v10::documents::*; -use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument}; -use Blockstamp; - -lazy_static! { - static ref REVOCATION_REGEX: Regex = Regex::new( - "^Issuer: (?P<issuer>[1-9A-Za-z][^OIl]{43,44})\n\ - IdtyUniqueID: (?P<idty_uid>[[:alnum:]_-]+)\n\ - IdtyTimestamp: (?P<idty_blockstamp>[0-9]+-[0-9A-F]{64})\n\ - IdtySignature: (?P<idty_sig>(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?)\n$" - ).unwrap(); -} +use pest::Parser; + +use blockstamp::Blockstamp; +use v10::*; +use *; #[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq, Eq)] /// Wrap an Compact Revocation document (in block content) @@ -106,7 +97,7 @@ impl Document for RevocationDocument { } fn as_bytes(&self) -> &[u8] { - self.as_text().as_bytes() + self.as_text_without_signature().as_bytes() } } @@ -198,26 +189,92 @@ IdtySignature: {idty_sig} #[derive(Debug, Clone, Copy)] pub struct RevocationDocumentParser; -impl StandardTextDocumentParser for RevocationDocumentParser { - fn parse_standard( - doc: &str, - body: &str, - currency: &str, - signatures: Vec<Sig>, - ) -> Result<V10Document, V10DocumentParsingError> { - if let Some(caps) = REVOCATION_REGEX.captures(body) { +impl TextDocumentParser for RevocationDocumentParser { + fn parse(doc: &str, currency: &str) -> Result<V10Document, V10DocumentParsingError> { + match DocumentsParser::parse(Rule::revoc, doc) { + Ok(mut doc_ast) => { + let revoc_ast = doc_ast.next().unwrap(); // get and unwrap the `revoc` rule; never fails + let revoc_vx_ast = revoc_ast.into_inner().next().unwrap(); // get and unwrap the `revoc_vX` rule; never fails + + match revoc_vx_ast.as_rule() { + Rule::revoc_v10 => { + let mut pubkeys = Vec::with_capacity(1); + let mut uid = ""; + let mut sigs = Vec::with_capacity(2); + let mut blockstamps = Vec::with_capacity(1); + for field in revoc_vx_ast.into_inner() { + match field.as_rule() { + Rule::currency => { + if currency != field.as_str() { + return Err(V10DocumentParsingError::InvalidCurrency()); + } + } + Rule::pubkey => { + if !pubkeys.is_empty() { + return Err(V10DocumentParsingError::InvalidInnerFormat( + "Revocation document must contain exactly one pubkey !", + )); + } + pubkeys.push(PubKey::Ed25519( + ed25519::PublicKey::from_base58(field.as_str()).unwrap(), // Grammar ensures that we have a base58 string. + )); + } + Rule::uid => { + uid = field.as_str(); + } + Rule::blockstamp => { + if blockstamps.len() > 1 { + return Err(V10DocumentParsingError::InvalidInnerFormat( + "Revocation document must contain exactly one blockstamp !", + )); + } + let mut inner_rules = field.into_inner(); // { integer ~ "-" ~ hash } + + let block_id: &str = inner_rules.next().unwrap().as_str(); + let block_hash: &str = inner_rules.next().unwrap().as_str(); + blockstamps.push(Blockstamp { + id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string. + hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string. + }); + } + Rule::ed25519_sig => { + sigs.push(Sig::Ed25519( + ed25519::Signature::from_base64(field.as_str()).unwrap(), // Grammar ensures that we have a base64 string. + )); + } + Rule::EOI => (), + _ => panic!("unexpected rule"), // Grammar ensures that we never reach this line + } + } + Ok(V10Document::Revocation(Box::new(RevocationDocument { + text: doc.to_owned(), + issuers: vec![pubkeys[0]], + currency: currency.to_owned(), + identity_username: uid.to_owned(), + identity_blockstamp: blockstamps[0], + identity_sig: sigs[0], + signatures: vec![sigs[1]], + }))) + } + _ => Err(V10DocumentParsingError::UnexpectedVersion()), + } + } + Err(pest_error) => panic!("{}", pest_error), //Err(V10DocumentParsingError::PestError()), + } + + /*if let Some(caps) = REVOCATION_REGEX.captures(body) { let issuer = &caps["issuer"]; let identity_username = &caps["idty_uid"]; let identity_blockstamp = &caps["idty_blockstamp"]; let identity_sig = &caps["idty_sig"]; - + // Regex match so should not fail. // TODO : Test it anyway let issuer = PubKey::Ed25519(ed25519::PublicKey::from_base58(issuer).unwrap()); let identity_username = String::from(identity_username); let identity_blockstamp = Blockstamp::from_string(identity_blockstamp).unwrap(); let identity_sig = Sig::Ed25519(Signature::from_base64(identity_sig).unwrap()); - + Ok(V10Document::Revocation(Box::new(RevocationDocument { text: doc.to_owned(), issuers: vec![issuer], @@ -228,18 +285,16 @@ impl StandardTextDocumentParser for RevocationDocumentParser { signatures, }))) } else { - Err(V10DocumentParsingError::InvalidInnerFormat( - "Revocation".to_string(), - )) - } + Err(V10DocumentParsingError::InvalidInnerFormat("Revocation")) + }*/ } } #[cfg(test)] mod tests { use super::*; - use blockchain::VerificationResult; use duniter_crypto::keys::{PrivateKey, PublicKey, Signature}; + use VerificationResult; #[test] fn generate_real_document() { @@ -288,17 +343,6 @@ mod tests { ); } - #[test] - fn revocation_standard_regex() { - assert!(REVOCATION_REGEX.is_match( - "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV -IdtyUniqueID: tic -IdtyTimestamp: 98221-000000575AC04F5164F7A307CDB766139EA47DD249E4A2444F292BC8AAB408B3 -IdtySignature: DjeipIeb/RF0tpVCnVnuw6mH1iLJHIsDfPGLR90Twy3PeoaDz6Yzhc/UjLWqHCi5Y6wYajV0dNg4jQRUneVBCQ== -" - )); - } - #[test] fn revocation_document() { let doc = "Version: 10 @@ -308,22 +352,11 @@ Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV IdtyUniqueID: tic IdtyTimestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 IdtySignature: 1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg== -"; - - let body = "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV -IdtyUniqueID: tic -IdtyTimestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -IdtySignature: 1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg== -"; +XXOgI++6qpY9O31ml/FcfbXCE6aixIrgkT5jL7kBle3YOMr+8wrp7Rt+z9hDVjrNfYX2gpeJsuMNfG4T/fzVDQ=="; let currency = "g1"; - let signatures = vec![Sig::Ed25519(ed25519::Signature::from_base64( -"XXOgI++6qpY9O31ml/FcfbXCE6aixIrgkT5jL7kBle3YOMr+8wrp7Rt+z9hDVjrNfYX2gpeJsuMNfG4T/fzVDQ==" - ).unwrap())]; - - let doc = - RevocationDocumentParser::parse_standard(doc, body, currency, signatures).unwrap(); + let doc = RevocationDocumentParser::parse(doc, currency).unwrap(); if let V10Document::Revocation(doc) = doc { println!("Doc : {:?}", doc); assert_eq!(doc.verify_signatures(), VerificationResult::Valid()) diff --git a/documents/blockchain/v10/documents/transaction.rs b/documents/src/v10/transaction.rs similarity index 62% rename from documents/blockchain/v10/documents/transaction.rs rename to documents/src/v10/transaction.rs index 077e335036cb48cf1f98198d922692760799e67b..8969526018579cf0970d60c5adf6bd35da745e9a 100644 --- a/documents/blockchain/v10/documents/transaction.rs +++ b/documents/src/v10/transaction.rs @@ -15,44 +15,17 @@ //! Wrappers around Transaction documents. -use blockchain::v10::documents::*; -use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument}; use crypto::digest::Digest; use crypto::sha2::Sha256; -use regex::Regex; -use regex::RegexBuilder; +use pest::iterators::Pair; +use pest::iterators::Pairs; +use pest::Parser; use std::ops::{Add, Deref, Sub}; use std::str::FromStr; -use {BlockId, Blockstamp, Hash}; - -lazy_static! { - static ref TRANSACTION_REGEX_SIZE: &'static usize = &40_000_000; - static ref TRANSACTION_REGEX_BUILDER: &'static str = - r"^Blockstamp: (?P<blockstamp>[0-9]+-[0-9A-F]{64})\nLocktime: (?P<locktime>[0-9]+)\nIssuers:(?P<issuers>(?:\n[1-9A-Za-z][^OIl]{43,44})+)Inputs:\n(?P<inputs>([0-9A-Za-z:]+\n)+)Unlocks:\n(?P<unlocks>([0-9]+:(SIG\([0-9]+\) ?|XHX\(\w+\) ?)+\n)+)Outputs:\n(?P<outputs>([0-9A-Za-z()&|: ]+\n)+)Comment: (?P<comment>[\\\w:/;*\[\]()?!^+=@&~#{}|<>%. -]{0,255})\n"; - static ref ISSUER_REGEX: Regex = Regex::new("(?P<issuer>[1-9A-Za-z]{43,44})\n").unwrap(); - static ref D_INPUT_REGEX: Regex = Regex::new( - "^(?P<amount>[1-9][0-9]*):(?P<base>[0-9]+):D:(?P<pubkey>[1-9A-Za-z]{43,44}):(?P<block_number>[0-9]+)$" - ).unwrap(); - static ref T_INPUT_REGEX: Regex = Regex::new( - "^(?P<amount>[1-9][0-9]*):(?P<base>[0-9]+):T:(?P<tx_hash>[0-9A-F]{64}):(?P<tx_index>[0-9]+)$" - ).unwrap(); - static ref UNLOCKS_REGEX: Regex = Regex::new( - r"^(?P<index>[0-9]+):(?P<unlocks>(SIG\([0-9]+\) ?|XHX\(\w+\) ?)+)$" - ).unwrap(); - static ref UNLOCK_SIG_REGEX: Regex = - Regex::new(r"^SIG\((?P<index>[0-9]+)\)$").unwrap(); - static ref UNLOCK_XHX_REGEX: Regex = Regex::new(r"^XHX\((?P<code>\w+)\)$").unwrap(); - static ref OUTPUT_COND_SIG_REGEX: Regex = Regex::new(r"^SIG\((?P<pubkey>[1-9A-Za-z]{43,44})\)*$").unwrap(); - static ref OUTPUT_COND_XHX_REGEX: Regex = Regex::new(r"^XHX\((?P<hash>[0-9A-F]{64})\)*$").unwrap(); - static ref OUTPUT_COND_CLTV_REGEX: Regex = Regex::new(r"^CLTV\((?P<timestamp>[0-9]+)\)*$").unwrap(); - static ref OUTPUT_COND_CSV_REGEX: Regex = Regex::new(r"^CSV\((?P<duration>[0-9]+)\)*$").unwrap(); - static ref OUPUT_CONDS_BRAKETS: Regex = Regex::new(r"^\((?P<conditions>[0-9A-Za-z()&| ]+)\)$").unwrap(); - static ref OUPUT_CONDS_AND: Regex = Regex::new(r"^(?P<conditions_group_1>[0-9A-Za-z()&| ]+) && (?P<conditions_group_2>[0-9A-Za-z()&| ]+)$").unwrap(); - static ref OUPUT_CONDS_OR: Regex = Regex::new(r"^(?P<conditions_group_1>[0-9A-Za-z()&| ]+) \|\| (?P<conditions_group_2>[0-9A-Za-z()&| ]+)$").unwrap(); - static ref OUTPUT_REGEX: Regex = Regex::new( - "^(?P<amount>[1-9][0-9]*):(?P<base>[0-9]+):(?P<conditions>[0-9A-Za-z()&| ]+)$" - ).unwrap(); -} + +use blockstamp::Blockstamp; +use v10::*; +use *; /// Wrap a transaction amount #[derive(Debug, Copy, Clone, Eq, Ord, PartialEq, PartialOrd, Deserialize, Hash, Serialize)] @@ -103,8 +76,55 @@ impl ToString for TransactionInput { } impl TransactionInput { + fn from_pest_pairs(mut pairs: Pairs<Rule>) -> TransactionInput { + let tx_input_type_pair = pairs.next().unwrap(); + match tx_input_type_pair.as_rule() { + Rule::tx_input_du => { + let mut inner_rules = tx_input_type_pair.into_inner(); // ${ tx_amount ~ ":" ~ tx_amount_base ~ ":D:" ~ pubkey ~ ":" ~ du_block_id } + + TransactionInput::D( + TxAmount(inner_rules.next().unwrap().as_str().parse().unwrap()), + TxBase(inner_rules.next().unwrap().as_str().parse().unwrap()), + PubKey::Ed25519( + ed25519::PublicKey::from_base58(inner_rules.next().unwrap().as_str()) + .unwrap(), + ), + BlockId(inner_rules.next().unwrap().as_str().parse().unwrap()), + ) + } + Rule::tx_input_tx => { + let mut inner_rules = tx_input_type_pair.into_inner(); // ${ tx_amount ~ ":" ~ tx_amount_base ~ ":D:" ~ pubkey ~ ":" ~ du_block_id } + + TransactionInput::T( + TxAmount(inner_rules.next().unwrap().as_str().parse().unwrap()), + TxBase(inner_rules.next().unwrap().as_str().parse().unwrap()), + Hash::from_hex(inner_rules.next().unwrap().as_str()).unwrap(), + TxIndex(inner_rules.next().unwrap().as_str().parse().unwrap()), + ) + } + _ => panic!("unexpected rule: {:?}", tx_input_type_pair.as_rule()), // Grammar ensures that we never reach this line + } + } +} + +impl FromStr for TransactionInput { + type Err = V10DocumentParsingError; + + fn from_str(source: &str) -> Result<Self, Self::Err> { + match DocumentsParser::parse(Rule::tx_input, source) { + Ok(mut pairs) => Ok(TransactionInput::from_pest_pairs( + pairs.next().unwrap().into_inner(), + )), + Err(_) => Err(V10DocumentParsingError::InvalidInnerFormat( + "Invalid unlocks !", + )), + } + } +} + +/*impl TransactionInput { /// Parse Transaction Input from string. - pub fn parse_from_str(source: &str) -> Result<TransactionInput, V10DocumentParsingError> { + pub fn from_str(source: &str) -> Result<TransactionInput, V10DocumentParsingError> { if let Some(caps) = D_INPUT_REGEX.captures(source) { let amount = &caps["amount"]; let base = &caps["base"]; @@ -136,12 +156,10 @@ impl TransactionInput { )) } else { println!("Fail to parse this input = {:?}", source); - Err(V10DocumentParsingError::InvalidInnerFormat(String::from( - "Transaction2", - ))) + Err(V10DocumentParsingError::InvalidInnerFormat("Transaction2")) } } -} +}*/ /// Wrap a transaction unlock proof #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] @@ -161,24 +179,6 @@ impl ToString for TransactionUnlockProof { } } -impl TransactionUnlockProof { - fn parse_from_str(source: &str) -> Result<TransactionUnlockProof, V10DocumentParsingError> { - if let Some(caps) = UNLOCK_SIG_REGEX.captures(source) { - let index = &caps["index"]; - Ok(TransactionUnlockProof::Sig( - index.parse().expect("fail to parse SIG unlock"), - )) - } else if let Some(caps) = UNLOCK_XHX_REGEX.captures(source) { - let code = &caps["code"]; - Ok(TransactionUnlockProof::Xhx(String::from(code))) - } else { - Err(V10DocumentParsingError::InvalidInnerFormat(String::from( - "Transaction3", - ))) - } - } -} - /// Wrap a transaction unlocks input #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] pub struct TransactionInputUnlocks { @@ -201,28 +201,46 @@ impl ToString for TransactionInputUnlocks { } impl TransactionInputUnlocks { - /// Parse Transaction Unlock from string. - pub fn parse_from_str( - source: &str, - ) -> Result<TransactionInputUnlocks, V10DocumentParsingError> { - if let Some(caps) = UNLOCKS_REGEX.captures(source) { - let index = &caps["index"].parse().expect("fail to parse unlock index"); - let unlocks = &caps["unlocks"]; - - let unlocks_array: Vec<&str> = unlocks.split(' ').collect(); - let mut unlocks = Vec::new(); - for unlock in unlocks_array { - unlocks.push(TransactionUnlockProof::parse_from_str(unlock)?); + fn from_pest_pairs(pairs: Pairs<Rule>) -> TransactionInputUnlocks { + let mut input_index = 0; + let mut unlock_conds = Vec::new(); + for unlock_field in pairs { + // ${ input_index ~ ":" ~ unlock_cond ~ (" " ~ unlock_cond)* } + match unlock_field.as_rule() { + Rule::input_index => input_index = unlock_field.as_str().parse().unwrap(), + Rule::unlock_sig => unlock_conds.push(TransactionUnlockProof::Sig( + unlock_field + .into_inner() + .next() + .unwrap() + .as_str() + .parse() + .unwrap(), + )), + Rule::unlock_xhx => unlock_conds.push(TransactionUnlockProof::Xhx(String::from( + unlock_field.into_inner().next().unwrap().as_str(), + ))), + _ => panic!("unexpected rule: {:?}", unlock_field.as_rule()), // Grammar ensures that we never reach this line } - Ok(TransactionInputUnlocks { - index: *index, - unlocks, - }) - } else { - println!("Fail to parse this unlock = {:?}", source); - Err(V10DocumentParsingError::InvalidInnerFormat(String::from( - "Transaction4", - ))) + } + TransactionInputUnlocks { + index: input_index, + unlocks: unlock_conds, + } + } +} + +impl FromStr for TransactionInputUnlocks { + type Err = V10DocumentParsingError; + + fn from_str(source: &str) -> Result<Self, Self::Err> { + match DocumentsParser::parse(Rule::tx_unlock, source) { + Ok(mut pairs) => Ok(TransactionInputUnlocks::from_pest_pairs( + pairs.next().unwrap().into_inner(), + )), + Err(_) => Err(V10DocumentParsingError::InvalidInnerFormat( + "Invalid unlocks !", + )), } } } @@ -251,48 +269,6 @@ impl ToString for TransactionOutputCondition { } } -impl TransactionOutputCondition { - fn parse_from_str(source: &str) -> Result<TransactionOutputCondition, V10DocumentParsingError> { - if let Some(caps) = OUTPUT_COND_SIG_REGEX.captures(source) { - if let Ok(pubkey) = ed25519::PublicKey::from_base58(&caps["pubkey"]) { - Ok(TransactionOutputCondition::Sig(PubKey::Ed25519(pubkey))) - } else { - Err(V10DocumentParsingError::InvalidInnerFormat(String::from( - "OutputCondition : Fail to parse SIG pubkey.", - ))) - } - } else if let Some(caps) = OUTPUT_COND_XHX_REGEX.captures(source) { - if let Ok(hash) = Hash::from_hex(&caps["hash"]) { - Ok(TransactionOutputCondition::Xhx(hash)) - } else { - Err(V10DocumentParsingError::InvalidInnerFormat(String::from( - "OutputCondition : Fail to parse XHX Hash.", - ))) - } - } else if let Some(caps) = OUTPUT_COND_CLTV_REGEX.captures(source) { - if let Ok(timestamp) = caps["timestamp"].parse() { - Ok(TransactionOutputCondition::Cltv(timestamp)) - } else { - Err(V10DocumentParsingError::InvalidInnerFormat(String::from( - "OutputCondition : Fail to parse CLTV timestamp.", - ))) - } - } else if let Some(caps) = OUTPUT_COND_CSV_REGEX.captures(source) { - if let Ok(duration) = caps["duration"].parse() { - Ok(TransactionOutputCondition::Csv(duration)) - } else { - Err(V10DocumentParsingError::InvalidInnerFormat(String::from( - "OutputCondition : Fail to parse CSV duraion.", - ))) - } - } else { - Err(V10DocumentParsingError::InvalidInnerFormat( - "Transaction5".to_string(), - )) - } - } -} - /// Wrap an utxo conditions #[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] pub struct UTXOConditions { @@ -329,17 +305,6 @@ impl ToString for UTXOConditions { } } -impl ::std::str::FromStr for UTXOConditions { - type Err = V10DocumentParsingError; - - fn from_str(source: &str) -> Result<Self, Self::Err> { - Ok(UTXOConditions { - origin_str: Some(String::from(source)), - conditions: UTXOConditionsGroup::from_str(source)?, - }) - } -} - /// Wrap a transaction ouput condition group #[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] pub enum UTXOConditionsGroup { @@ -353,6 +318,79 @@ pub enum UTXOConditionsGroup { Or(Box<UTXOConditionsGroup>, Box<UTXOConditionsGroup>), } +macro_rules! utxo_conds_wrap_op_chain { + ($op:expr, $fn_name:ident) => { + fn $fn_name(conds_subgroups: &mut Vec<UTXOConditionsGroup>) -> UTXOConditionsGroup { + if conds_subgroups.len() == 2 { + $op( + Box::new(conds_subgroups[0].clone()), + Box::new(conds_subgroups[1].clone()), + ) + } else if conds_subgroups.len() > 2 { + let last_subgroup = conds_subgroups.pop().unwrap(); + let previous_last_subgroup = conds_subgroups.pop().unwrap(); + conds_subgroups.push($op( + Box::new(previous_last_subgroup), + Box::new(last_subgroup), + )); + UTXOConditionsGroup::$fn_name(conds_subgroups) + } else { + panic!( + "Grammar should ensure that and chain contains at least two conditions subgroups !" + ) + } + } + } +} + +impl UTXOConditionsGroup { + /// Wrap UTXO and chain + utxo_conds_wrap_op_chain!(UTXOConditionsGroup::And, new_and_chain); + /// Wrap UTXO or chain + utxo_conds_wrap_op_chain!(UTXOConditionsGroup::Or, new_or_chain); + + /// Wrap UTXO conditions + pub fn wrap_utxo_conds(pair: Pair<Rule>) -> UTXOConditionsGroup { + match pair.as_rule() { + Rule::output_and_group => { + let mut and_pairs = pair.into_inner(); + let mut conds_subgroups: Vec<UTXOConditionsGroup> = and_pairs + .map(UTXOConditionsGroup::wrap_utxo_conds) + .collect(); + UTXOConditionsGroup::Brackets(Box::new(UTXOConditionsGroup::new_and_chain( + &mut conds_subgroups, + ))) + } + Rule::output_or_group => { + let mut or_pairs = pair.into_inner(); + let mut conds_subgroups: Vec<UTXOConditionsGroup> = + or_pairs.map(UTXOConditionsGroup::wrap_utxo_conds).collect(); + UTXOConditionsGroup::Brackets(Box::new(UTXOConditionsGroup::new_or_chain( + &mut conds_subgroups, + ))) + } + Rule::output_cond_sig => { + UTXOConditionsGroup::Single(TransactionOutputCondition::Sig(PubKey::Ed25519( + ed25519::PublicKey::from_base58(pair.into_inner().next().unwrap().as_str()) + .unwrap(), + ))) + } + Rule::output_cond_xhx => UTXOConditionsGroup::Single(TransactionOutputCondition::Xhx( + Hash::from_hex(pair.into_inner().next().unwrap().as_str()).unwrap(), + )), + Rule::output_cond_csv => UTXOConditionsGroup::Single(TransactionOutputCondition::Csv( + pair.into_inner().next().unwrap().as_str().parse().unwrap(), + )), + Rule::output_cond_cltv => { + UTXOConditionsGroup::Single(TransactionOutputCondition::Cltv( + pair.into_inner().next().unwrap().as_str().parse().unwrap(), + )) + } + _ => panic!("unexpected rule: {:?}", pair.as_rule()), // Grammar ensures that we never reach this line + } + } +} + impl ToString for UTXOConditionsGroup { fn to_string(&self) -> String { match *self { @@ -374,38 +412,6 @@ impl ToString for UTXOConditionsGroup { } } -impl ::std::str::FromStr for UTXOConditionsGroup { - type Err = V10DocumentParsingError; - - fn from_str(conditions: &str) -> Result<Self, Self::Err> { - if let Ok(single_condition) = TransactionOutputCondition::parse_from_str(conditions) { - Ok(UTXOConditionsGroup::Single(single_condition)) - } else if let Some(caps) = OUPUT_CONDS_BRAKETS.captures(conditions) { - let inner_conditions = UTXOConditionsGroup::from_str(&caps["conditions"])?; - Ok(UTXOConditionsGroup::Brackets(Box::new(inner_conditions))) - } else if let Some(caps) = OUPUT_CONDS_AND.captures(conditions) { - let conditions_group_1 = UTXOConditionsGroup::from_str(&caps["conditions_group_1"])?; - let conditions_group_2 = UTXOConditionsGroup::from_str(&caps["conditions_group_2"])?; - Ok(UTXOConditionsGroup::And( - Box::new(conditions_group_1), - Box::new(conditions_group_2), - )) - } else if let Some(caps) = OUPUT_CONDS_OR.captures(conditions) { - let conditions_group_1 = UTXOConditionsGroup::from_str(&caps["conditions_group_1"])?; - let conditions_group_2 = UTXOConditionsGroup::from_str(&caps["conditions_group_2"])?; - Ok(UTXOConditionsGroup::Or( - Box::new(conditions_group_1), - Box::new(conditions_group_2), - )) - } else { - println!("fail to parse this output condition = {:?}", conditions); - Err(V10DocumentParsingError::InvalidInnerFormat(String::from( - "Transaction6", - ))) - } - } -} - /// Wrap a transaction ouput #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] pub struct TransactionOutput { @@ -440,21 +446,33 @@ impl ToString for TransactionOutput { } impl TransactionOutput { - /// Parse Transaction Output from string. - pub fn parse_from_str(source: &str) -> Result<TransactionOutput, V10DocumentParsingError> { - if let Some(caps) = OUTPUT_REGEX.captures(source) { - let amount = TxAmount(caps["amount"].parse().expect("fail to parse output amount")); - let base = TxBase(caps["base"].parse().expect("fail to parse base amount")); - let conditions = UTXOConditions::from_str(&caps["conditions"])?; - Ok(TransactionOutput { - conditions, - amount, - base, - }) - } else { - Err(V10DocumentParsingError::InvalidInnerFormat( - "Transaction7".to_string(), - )) + fn from_pest_pairs(mut utxo_pairs: Pairs<Rule>) -> TransactionOutput { + let amount = TxAmount(utxo_pairs.next().unwrap().as_str().parse().unwrap()); + let base = TxBase(utxo_pairs.next().unwrap().as_str().parse().unwrap()); + let conditions_pairs = utxo_pairs.next().unwrap(); + let conditions_origin_str = conditions_pairs.as_str(); + TransactionOutput { + amount, + base, + conditions: UTXOConditions { + origin_str: Some(String::from(conditions_origin_str)), + conditions: UTXOConditionsGroup::wrap_utxo_conds(conditions_pairs), + }, + } + } +} + +impl FromStr for TransactionOutput { + type Err = V10DocumentParsingError; + + fn from_str(source: &str) -> Result<Self, Self::Err> { + match DocumentsParser::parse(Rule::tx_output, source) { + Ok(mut utxo_pairs) => Ok(TransactionOutput::from_pest_pairs( + utxo_pairs.next().unwrap().into_inner(), + )), + Err(_) => Err(V10DocumentParsingError::InvalidInnerFormat( + "Invalid output !", + )), } } } @@ -563,7 +581,7 @@ impl Document for TransactionDocument { } fn as_bytes(&self) -> &[u8] { - self.as_text().as_bytes() + self.as_text_without_signature().as_bytes() } } @@ -743,72 +761,80 @@ Issuers: #[derive(Debug, Clone, Copy)] pub struct TransactionDocumentParser; -impl StandardTextDocumentParser for TransactionDocumentParser { - fn parse_standard( - doc: &str, - body: &str, - currency: &str, - signatures: Vec<Sig>, - ) -> Result<V10Document, V10DocumentParsingError> { - let tx_regex: Regex = RegexBuilder::new(&TRANSACTION_REGEX_BUILDER) - .size_limit(**TRANSACTION_REGEX_SIZE) - .build() - .expect("fail to build TRANSACTION_REGEX !"); - if let Some(caps) = tx_regex.captures(body) { - let blockstamp = - Blockstamp::from_string(&caps["blockstamp"]).expect("fail to parse blockstamp"); - let locktime = caps["locktime"].parse().expect("fail to parse locktime"); - let issuers_str = &caps["issuers"]; - let inputs = &caps["inputs"]; - let unlocks = &caps["unlocks"]; - let outputs = &caps["outputs"]; - let comment = String::from(&caps["comment"]); - - let mut issuers = Vec::new(); - for caps in ISSUER_REGEX.captures_iter(issuers_str) { - issuers.push(PubKey::Ed25519( - ed25519::PublicKey::from_base58(&caps["issuer"]).expect("fail to parse issuer"), - )); - } - let inputs_array: Vec<&str> = inputs.split('\n').collect(); - let mut inputs = Vec::new(); - for input in inputs_array { - if !input.is_empty() { - inputs.push(TransactionInput::parse_from_str(input)?); - } - } - let unlocks_array: Vec<&str> = unlocks.split('\n').collect(); - let mut unlocks = Vec::new(); - for unlock in unlocks_array { - if !unlock.is_empty() { - unlocks.push(TransactionInputUnlocks::parse_from_str(unlock)?); +impl TextDocumentParser for TransactionDocumentParser { + fn parse(doc: &str, currency: &str) -> Result<V10Document, V10DocumentParsingError> { + match DocumentsParser::parse(Rule::tx, doc) { + Ok(mut doc_ast) => { + let tx_ast = doc_ast.next().unwrap(); // get and unwrap the `tx` rule; never fails + let tx_vx_ast = tx_ast.into_inner().next().unwrap(); // get and unwrap the `tx_vX` rule; never fails + + match tx_vx_ast.as_rule() { + Rule::tx_v10 => { + let mut blockstamp = Blockstamp::default(); + let mut locktime = 0; + let mut issuers = Vec::new(); + let mut inputs = Vec::new(); + let mut unlocks = Vec::new(); + let mut outputs = Vec::new(); + let mut comment = ""; + let mut sigs = Vec::new(); + + for field in tx_vx_ast.into_inner() { + match field.as_rule() { + Rule::currency => { + if currency != field.as_str() { + return Err(V10DocumentParsingError::InvalidCurrency()); + } + } + Rule::blockstamp => { + let mut inner_rules = field.into_inner(); // ${ block_id ~ "-" ~ hash } + + let block_id: &str = inner_rules.next().unwrap().as_str(); + let block_hash: &str = inner_rules.next().unwrap().as_str(); + blockstamp = Blockstamp { + id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string. + hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string. + }; + } + Rule::tx_locktime => locktime = field.as_str().parse().unwrap(), // Grammar ensures that we have digits characters. + Rule::pubkey => issuers.push(PubKey::Ed25519( + ed25519::PublicKey::from_base58(field.as_str()).unwrap(), // Grammar ensures that we have a base58 string. + )), + Rule::tx_input => inputs + .push(TransactionInput::from_pest_pairs(field.into_inner())), + Rule::tx_unlock => unlocks.push( + TransactionInputUnlocks::from_pest_pairs(field.into_inner()), + ), + Rule::tx_output => outputs + .push(TransactionOutput::from_pest_pairs(field.into_inner())), + Rule::tx_comment => comment = field.as_str(), + Rule::ed25519_sig => { + sigs.push(Sig::Ed25519( + ed25519::Signature::from_base64(field.as_str()).unwrap(), // Grammar ensures that we have a base64 string. + )); + } + Rule::EOI => (), + _ => panic!("unexpected rule: {:?}", field.as_rule()), // Grammar ensures that we never reach this line + } + } + Ok(V10Document::Transaction(Box::new(TransactionDocument { + text: Some(doc.to_owned()), + currency: currency.to_owned(), + blockstamp, + locktime, + issuers, + inputs, + unlocks, + outputs, + comment: comment.to_owned(), + signatures: sigs, + hash: None, + }))) + } + _ => Err(V10DocumentParsingError::UnexpectedVersion()), } } - let outputs_array: Vec<&str> = outputs.split('\n').collect(); - let mut outputs = Vec::new(); - for output in outputs_array { - if !output.is_empty() { - outputs.push(TransactionOutput::parse_from_str(output)?); - } - } - - Ok(V10Document::Transaction(Box::new(TransactionDocument { - text: Some(doc.to_owned()), - currency: currency.to_owned(), - blockstamp, - locktime, - issuers, - inputs, - unlocks, - outputs, - comment, - signatures, - hash: None, - }))) - } else { - Err(V10DocumentParsingError::InvalidInnerFormat( - "Transaction1".to_string(), - )) + Err(pest_error) => panic!("{}", pest_error), //Err(V10DocumentParsingError::PestError()), } } } @@ -816,7 +842,7 @@ impl StandardTextDocumentParser for TransactionDocumentParser { #[cfg(test)] mod tests { use super::*; - use blockchain::{Document, VerificationResult}; + use {Document, VerificationResult}; #[test] fn generate_real_document() { @@ -847,13 +873,20 @@ mod tests { blockstamp: &block, locktime: &0, issuers: &vec![pubkey], - inputs: &vec![TransactionInput::parse_from_str( - "10:0:D:DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV:0", - ) - .expect("fail to parse input !")], - unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)") - .expect("fail to parse unlock !")], - outputs: &vec![TransactionOutput::parse_from_str( + inputs: &vec![TransactionInput::D( + TxAmount(10), + TxBase(0), + PubKey::Ed25519( + ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV") + .unwrap(), + ), + BlockId(0), + )], + unlocks: &vec![TransactionInputUnlocks { + index: 0, + unlocks: vec![TransactionUnlockProof::Sig(0)], + }], + outputs: &vec![TransactionOutput::from_str( "10:0:SIG(FD9wujR7KABw88RyKEGBYRLz8PA6jzVCbcBAsrBXBqSa)", ) .expect("fail to parse output !")], @@ -895,18 +928,22 @@ mod tests { blockstamp: &block, locktime: &0, issuers: &vec![pubkey], - inputs: &vec![TransactionInput::parse_from_str( - "950:0:T:2CF1ACD8FE8DC93EE39A1D55881C50D87C55892AE8E4DB71D4EBAB3D412AA8FD:1", - ) - .expect("fail to parse input !")], - unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)") - .expect("fail to parse unlock !")], + inputs: &vec![TransactionInput::T( + TxAmount(950), + TxBase(0), + Hash::from_hex("2CF1ACD8FE8DC93EE39A1D55881C50D87C55892AE8E4DB71D4EBAB3D412AA8FD") + .unwrap(), + TxIndex(1), + )], + unlocks: &vec![ + TransactionInputUnlocks::from_str("0:SIG(0)").expect("fail to parse unlock !") + ], outputs: &vec![ - TransactionOutput::parse_from_str( + TransactionOutput::from_str( "30:0:SIG(38MEAZN68Pz1DTvT3tqgxx4yQP6snJCQhPqEFxbDk4aE)", ) .expect("fail to parse output !"), - TransactionOutput::parse_from_str( + TransactionOutput::from_str( "920:0:SIG(FEkbc4BfJukSWnCU6Hed6dgwwTuPFTVdgz5LpL4iHr9J)", ) .expect("fail to parse output !"), @@ -924,42 +961,6 @@ mod tests { ); } - #[test] - fn transaction_standard_regex() { - let tx_regex: Regex = RegexBuilder::new(&TRANSACTION_REGEX_BUILDER) - .size_limit(**TRANSACTION_REGEX_SIZE) - .build() - .expect("fail to build TRANSACTION_REGEX !"); - assert!(tx_regex.is_match( - "Blockstamp: 204-00003E2B8A35370BA5A7064598F628A62D4E9EC1936BE8651CE9A85F2E06981B -Locktime: 0 -Issuers: -HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY -CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp -FD9wujR7KABw88RyKEGBYRLz8PA6jzVCbcBAsrBXBqSa -Inputs: -40:2:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2 -70:2:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8 -20:2:D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:46 -70:2:T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3 -20:2:T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5 -15:2:D:FD9wujR7KABw88RyKEGBYRLz8PA6jzVCbcBAsrBXBqSa:46 -Unlocks: -0:SIG(0) -1:XHX(7665798292) -2:SIG(0) -3:SIG(0) SIG(2) -4:SIG(0) SIG(1) SIG(2) -5:SIG(2) -Outputs: -120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g) -146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx) -49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85)) -Comment: -----@@@----- (why not this comment?) -" - )); - } - #[test] fn parse_transaction_document() { let doc = "Version: 10 @@ -990,51 +991,13 @@ Outputs: 146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx) 49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85F2AC2FD3FA4FDC46A4FC01CA)) Comment: -----@@@----- (why not this comment?) -"; - - let body = - "Blockstamp: 204-00003E2B8A35370BA5A7064598F628A62D4E9EC1936BE8651CE9A85F2E06981B -Locktime: 0 -Issuers: -DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV -4tNQ7d9pj2Da5wUVoW9mFn7JjuPoowF977au8DdhEjVR -FD9wujR7KABw88RyKEGBYRLz8PA6jzVCbcBAsrBXBqSa -Inputs: -40:2:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2 -70:2:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8 -20:2:D:DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV:46 -70:2:T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3 -20:2:T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5 -15:2:D:FD9wujR7KABw88RyKEGBYRLz8PA6jzVCbcBAsrBXBqSa:46 -Unlocks: -0:SIG(0) -1:XHX(7665798292) -2:SIG(0) -3:SIG(0) SIG(2) -4:SIG(0) SIG(1) SIG(2) -5:SIG(2) -Outputs: -120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g) -146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx) -49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85F2AC2FD3FA4FDC46A4FC01CA)) -Comment: -----@@@----- (why not this comment?) -"; +kL59C1izKjcRN429AlKdshwhWbasvyL7sthI757zm1DfZTdTIctDWlKbYeG/tS7QyAgI3gcfrTHPhu1E1lKCBw== +e3LpgB2RZ/E/BCxPJsn+TDDyxGYzrIsMyDt//KhJCjIQD6pNUxr5M5jrq2OwQZgwmz91YcmoQ2XRQAUDpe4BAw== +w69bYgiQxDmCReB0Dugt9BstXlAKnwJkKCdWvCeZ9KnUCv0FJys6klzYk/O/b9t74tYhWZSX0bhETWHiwfpWBw=="; let currency = "duniter_unit_test_currency"; - let signatures = vec![ - Sig::Ed25519(ed25519::Signature::from_base64( -"kL59C1izKjcRN429AlKdshwhWbasvyL7sthI757zm1DfZTdTIctDWlKbYeG/tS7QyAgI3gcfrTHPhu1E1lKCBw==" - ).expect("fail to parse test signature")), - Sig::Ed25519(ed25519::Signature::from_base64( -"e3LpgB2RZ/E/BCxPJsn+TDDyxGYzrIsMyDt//KhJCjIQD6pNUxr5M5jrq2OwQZgwmz91YcmoQ2XRQAUDpe4BAw==" - ).expect("fail to parse test signature")), - Sig::Ed25519(ed25519::Signature::from_base64( -"w69bYgiQxDmCReB0Dugt9BstXlAKnwJkKCdWvCeZ9KnUCv0FJys6klzYk/O/b9t74tYhWZSX0bhETWHiwfpWBw==" - ).expect("fail to parse test signature")), - ]; - - let doc = TransactionDocumentParser::parse_standard(doc, body, currency, signatures) + let doc = TransactionDocumentParser::parse(doc, currency) .expect("fail to parse test transaction document !"); if let V10Document::Transaction(doc) = doc { //println!("Doc : {:?}", doc); diff --git a/message/lib.rs b/message/lib.rs index d8bf3a8b710de4537c30fb65b710abd285184220..b6d75d48790c2a630ee1f9ba69dc04fb0798be8b 100644 --- a/message/lib.rs +++ b/message/lib.rs @@ -41,8 +41,8 @@ use duniter_crypto::hashs::Hash; use duniter_crypto::keys::Sig; use duniter_dal::dal_event::DALEvent; use duniter_dal::dal_requests::{DALRequest, DALResponse}; -use duniter_documents::blockchain::BlockchainProtocol; use duniter_documents::BlockId; +use duniter_documents::BlockchainProtocol; use duniter_module::*; use duniter_network::{NetworkEvent, NetworkResponse, OldNetworkRequest}; diff --git a/network/lib.rs b/network/lib.rs index 4a0ed49cb6d8d5f695c5857712e7a8bb7efc7098..b8de326f9daf90f67ae44a41fcafeca65b330bc4 100644 --- a/network/lib.rs +++ b/network/lib.rs @@ -55,12 +55,14 @@ use crypto::digest::Digest; use crypto::sha2::Sha256; use duniter_crypto::hashs::*; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::{ - BlockDocument, CertificationDocument, IdentityDocument, MembershipDocument, RevocationDocument, - TransactionDocument, -}; -use duniter_documents::blockchain::Document; -use duniter_documents::{BlockHash, BlockId, Blockstamp}; +use duniter_documents::v10::block::BlockDocument; +use duniter_documents::v10::certification::CertificationDocument; +use duniter_documents::v10::identity::IdentityDocument; +use duniter_documents::v10::membership::MembershipDocument; +use duniter_documents::v10::revocation::RevocationDocument; +use duniter_documents::v10::transaction::TransactionDocument; +use duniter_documents::Document; +use duniter_documents::{blockstamp::Blockstamp, BlockHash, BlockId}; use duniter_module::*; use network_endpoint::ApiFeatures; use network_head::NetworkHead; diff --git a/network/network_head.rs b/network/network_head.rs index 922989510a9dc149d306a6f0b8070853b8aa7b80..9c5d1c023e11170eebcfc2619e7e77719e044d82 100644 --- a/network/network_head.rs +++ b/network/network_head.rs @@ -16,8 +16,7 @@ //! Module defining the format of network heads and how to handle them. use duniter_crypto::keys::*; -use duniter_documents::BlockUIdParseError; -use duniter_documents::Blockstamp; +use duniter_documents::blockstamp::*; use network_head_v2::*; use network_head_v3::*; use serde_json; @@ -52,8 +51,8 @@ pub enum NetworkHeadParseErr { BaseConvertionError(BaseConvertionError), /// ParseIntError ParseIntError(ParseIntError), - /// BlockUIdParseError - BlockUIdParseError(BlockUIdParseError), + /// BlockstampParseError + BlockstampParseError(BlockstampParseError), /// NetworkHeadMessageParseErr NetworkHeadMessageParseErr(NetworkHeadMessageParseErr), /// InvalidMessageVersion @@ -78,9 +77,9 @@ impl From<BaseConvertionError> for NetworkHeadParseErr { } } -impl From<BlockUIdParseError> for NetworkHeadParseErr { - fn from(e: BlockUIdParseError) -> Self { - NetworkHeadParseErr::BlockUIdParseError(e) +impl From<BlockstampParseError> for NetworkHeadParseErr { + fn from(e: BlockstampParseError) -> Self { + NetworkHeadParseErr::BlockstampParseError(e) } } diff --git a/network/network_head_v2.rs b/network/network_head_v2.rs index 25fa81c11786db8b4c0bd9e7e6abd9c89d3589c4..bae01eac58023fb905afe5727e23b0e09d1178df 100644 --- a/network/network_head_v2.rs +++ b/network/network_head_v2.rs @@ -16,8 +16,7 @@ //! Module defining the format of network heads v2 and how to handle them. use duniter_crypto::keys::*; -use duniter_documents::BlockUIdParseError; -use duniter_documents::Blockstamp; +use duniter_documents::blockstamp::*; use std::cmp::Ordering; use std::num::ParseIntError; use std::ops::Deref; @@ -145,8 +144,8 @@ pub enum NetworkHeadMessageParseErr { BaseConvertionError(BaseConvertionError), /// ParseIntError ParseIntError(ParseIntError), - /// BlockUIdParseError - BlockUIdParseError(BlockUIdParseError), + /// BlockstampParseError + BlockstampParseError(BlockstampParseError), } impl From<BaseConvertionError> for NetworkHeadMessageParseErr { @@ -155,9 +154,9 @@ impl From<BaseConvertionError> for NetworkHeadMessageParseErr { } } -impl From<BlockUIdParseError> for NetworkHeadMessageParseErr { - fn from(e: BlockUIdParseError) -> Self { - NetworkHeadMessageParseErr::BlockUIdParseError(e) +impl From<BlockstampParseError> for NetworkHeadMessageParseErr { + fn from(e: BlockstampParseError) -> Self { + NetworkHeadMessageParseErr::BlockstampParseError(e) } } diff --git a/network/network_head_v3.rs b/network/network_head_v3.rs index b227b94b1d4ce0f0195a2e32fee488f5e0af62dd..611c9807c808a1253c4bb9428595b97c4d61f2ec 100644 --- a/network/network_head_v3.rs +++ b/network/network_head_v3.rs @@ -18,7 +18,7 @@ use base58::ToBase58; use duniter_crypto::keys::bin_signable::BinSignable; use duniter_crypto::keys::*; -use duniter_documents::Blockstamp; +use duniter_documents::blockstamp::Blockstamp; use serde_json; use std::cmp::Ordering; use NodeId; diff --git a/network/network_peer.rs b/network/network_peer.rs index d0b7bf9f30acc55155456c3811f43129bd857364..caacd3390e0074170d42127c39a2117757deaf94 100644 --- a/network/network_peer.rs +++ b/network/network_peer.rs @@ -24,7 +24,7 @@ extern crate serde; use base58::ToBase58; use duniter_crypto::keys::bin_signable::BinSignable; use duniter_crypto::keys::*; -use duniter_documents::{Blockstamp, CurrencyName}; +use duniter_documents::{blockstamp::Blockstamp, CurrencyName}; use network_endpoint::*; use *; diff --git a/ws2p-messages/lib.rs b/ws2p-messages/lib.rs index 1588f275e38dd34b9485c3882b096dee74deb6c8..f3f2e9b7ecd7d9e11fa2a17abf6fd0bf70c820bd 100644 --- a/ws2p-messages/lib.rs +++ b/ws2p-messages/lib.rs @@ -58,7 +58,7 @@ mod tests { use bincode::{deserialize, serialize}; use duniter_crypto::keys::bin_signable::BinSignable; use duniter_crypto::keys::*; - use duniter_documents::blockchain::v10::documents::certification::*; + use duniter_documents::v10::certification::*; use duniter_documents::{Blockstamp, CurrencyName}; use duniter_network::network_endpoint::*; use duniter_network::network_peer::*; diff --git a/ws2p-messages/v2/payload_container.rs b/ws2p-messages/v2/payload_container.rs index 9ff1dec581943c9149415c5dcbe801b067b84cde..473502878493826dbc59b6c4b61a26378b9014f2 100644 --- a/ws2p-messages/v2/payload_container.rs +++ b/ws2p-messages/v2/payload_container.rs @@ -19,10 +19,12 @@ use super::req_responses::WS2Pv2ReqRes; use super::requests::WS2Pv2Request; use super::secret_flags::WS2Pv2SecretFlagsMsg; use duniter_crypto::hashs::Hash; -use duniter_documents::blockchain::v10::documents::{ - BlockDocument, CertificationDocument, IdentityDocument, MembershipDocument, RevocationDocument, - TransactionDocument, -}; +use duniter_documents::v10::block::BlockDocument; +use duniter_documents::v10::certification::CertificationDocument; +use duniter_documents::v10::identity::IdentityDocument; +use duniter_documents::v10::membership::MembershipDocument; +use duniter_documents::v10::revocation::RevocationDocument; +use duniter_documents::v10::transaction::TransactionDocument; use duniter_network::network_head_v2::NetworkHeadV2; use duniter_network::network_head_v3::NetworkHeadV3Container; use duniter_network::network_peer::PeerCardV11; diff --git a/ws2p-messages/v2/req_responses.rs b/ws2p-messages/v2/req_responses.rs index ed81adbc5cfc62e6d4d2dd133284877f4e025aff..c4010b2f80a3a66aa61ff2c7dab9095e8f0a1279 100644 --- a/ws2p-messages/v2/req_responses.rs +++ b/ws2p-messages/v2/req_responses.rs @@ -14,10 +14,10 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. use duniter_crypto::hashs::Hash; -use duniter_documents::blockchain::v10::documents::certification::CompactCertificationDocument; -use duniter_documents::blockchain::v10::documents::identity::CompactIdentityDocument; -use duniter_documents::blockchain::v10::documents::membership::CompactPoolMembershipDoc; -use duniter_documents::blockchain::v10::documents::BlockDocument; +use duniter_documents::v10::block::BlockDocument; +use duniter_documents::v10::certification::CompactCertificationDocument; +use duniter_documents::v10::identity::CompactIdentityDocument; +use duniter_documents::v10::membership::CompactPoolMembershipDoc; use duniter_documents::Blockstamp; use std::str; diff --git a/ws2p-v1-legacy/lib.rs b/ws2p-v1-legacy/lib.rs index 3e7e662f35b8f887f26bf62d70f125c1b098b06f..1406c811f9433ad90eb490fd6b3a2312e5b96657 100644 --- a/ws2p-v1-legacy/lib.rs +++ b/ws2p-v1-legacy/lib.rs @@ -929,7 +929,7 @@ mod tests { use super::parsers::blocks::parse_json_block; use super::*; use duniter_crypto::keys::PublicKey; - use duniter_documents::blockchain::v10::documents::BlockDocument; + use duniter_documents::v10::BlockDocument; use duniter_module::DuniterModule; use duniter_network::network_endpoint::{EndpointEnum, NetworkEndpointApi}; use duniter_network::NetworkBlock; diff --git a/ws2p-v1-legacy/parsers/blocks.rs b/ws2p-v1-legacy/parsers/blocks.rs index ae3aa8dd3ea4b0475bc84275974742830f653e52..867e97070e8c0e28493d3154cb75af74596abc7b 100644 --- a/ws2p-v1-legacy/parsers/blocks.rs +++ b/ws2p-v1-legacy/parsers/blocks.rs @@ -5,9 +5,9 @@ use super::identities::parse_compact_identity; use super::transactions::parse_transaction; use duniter_crypto::hashs::Hash; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::block::{BlockV10Parameters, TxDocOrTxHash}; -use duniter_documents::blockchain::v10::documents::membership::*; -use duniter_documents::blockchain::v10::documents::BlockDocument; +use duniter_documents::v10::block::{BlockV10Parameters, TxDocOrTxHash}; +use duniter_documents::v10::membership::*; +use duniter_documents::v10::BlockDocument; use duniter_documents::CurrencyName; use duniter_documents::{BlockHash, BlockId}; use duniter_network::{NetworkBlock, NetworkBlockV10}; diff --git a/ws2p-v1-legacy/parsers/identities.rs b/ws2p-v1-legacy/parsers/identities.rs index ef62335415055c325cef050850d8957efc949fb9..1d288f6db6b03f9c4dd983ff74d2a4320ed6a7b7 100644 --- a/ws2p-v1-legacy/parsers/identities.rs +++ b/ws2p-v1-legacy/parsers/identities.rs @@ -1,10 +1,9 @@ extern crate serde_json; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::identity::IdentityDocumentBuilder; -use duniter_documents::blockchain::v10::documents::IdentityDocument; -use duniter_documents::blockchain::DocumentBuilder; +use duniter_documents::v10::identity::*; use duniter_documents::Blockstamp; +use duniter_documents::DocumentBuilder; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum IdentityParseError { diff --git a/ws2p-v1-legacy/parsers/memberships.rs b/ws2p-v1-legacy/parsers/memberships.rs index a193d5e64ea9ed393bd606eb63b85fd4a29d77a2..496a1c4b84ba4cb11960c7d34c9c7f1ee055dd2c 100644 --- a/ws2p-v1-legacy/parsers/memberships.rs +++ b/ws2p-v1-legacy/parsers/memberships.rs @@ -1,12 +1,9 @@ extern crate serde_json; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::membership::{ - MembershipDocumentBuilder, MembershipType, -}; -use duniter_documents::blockchain::v10::documents::MembershipDocument; -use duniter_documents::blockchain::DocumentBuilder; +use duniter_documents::v10::membership::*; use duniter_documents::Blockstamp; +use duniter_documents::DocumentBuilder; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum MembershipParseError { diff --git a/ws2p-v1-legacy/parsers/mod.rs b/ws2p-v1-legacy/parsers/mod.rs index decd00fa29656b549f201a620fdfb6ae7c269682..fec21d7a728fb1c7714ee5e0c477603fbf996c8d 100644 --- a/ws2p-v1-legacy/parsers/mod.rs +++ b/ws2p-v1-legacy/parsers/mod.rs @@ -23,9 +23,10 @@ pub mod transactions; mod tests { use super::transactions::*; use duniter_crypto::keys::*; - use duniter_documents::blockchain::v10::documents::transaction::*; - use duniter_documents::blockchain::DocumentBuilder; + use duniter_documents::v10::transaction::*; use duniter_documents::Blockstamp; + use duniter_documents::DocumentBuilder; + use std::str::FromStr; #[test] fn parse_json_tx() { @@ -65,15 +66,15 @@ mod tests { ed25519::PublicKey::from_base58("51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2") .unwrap(), )], - inputs: &vec![TransactionInput::parse_from_str( + inputs: &vec![TransactionInput::from_str( "1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496", ) .unwrap()], - outputs: &vec![TransactionOutput::parse_from_str( + outputs: &vec![TransactionOutput::from_str( "1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)", ) .unwrap()], - unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)").unwrap()], + unlocks: &vec![TransactionInputUnlocks::from_str("0:SIG(0)").unwrap()], comment: "Merci pour la calligraphie ;) de Liam", hash: None, }; @@ -124,21 +125,19 @@ mod tests { ed25519::PublicKey::from_base58("FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD") .unwrap(), )], - inputs: &vec![TransactionInput::parse_from_str( + inputs: &vec![TransactionInput::from_str( "1000:0:D:FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD:1", ) .unwrap()], outputs: &vec![ - TransactionOutput::parse_from_str( - "3:0:SIG(7vU9BMDhN6fBuRa2iK3JRbC6pqQKb4qDMGsFcQuT5cz)", - ) - .unwrap(), - TransactionOutput::parse_from_str( + TransactionOutput::from_str("3:0:SIG(7vU9BMDhN6fBuRa2iK3JRbC6pqQKb4qDMGsFcQuT5cz)") + .unwrap(), + TransactionOutput::from_str( "997:0:SIG(FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD)", ) .unwrap(), ], - unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)").unwrap()], + unlocks: &vec![TransactionInputUnlocks::from_str("0:SIG(0)").unwrap()], comment: "Un petit cafe ;-)", hash: None, }; diff --git a/ws2p-v1-legacy/parsers/transactions.rs b/ws2p-v1-legacy/parsers/transactions.rs index ff24ff9e7c3a5836f485b8752ae606046c4a1349..5f4b700520caf045f784ebd3e8a49a1e64a1b685 100644 --- a/ws2p-v1-legacy/parsers/transactions.rs +++ b/ws2p-v1-legacy/parsers/transactions.rs @@ -3,12 +3,13 @@ extern crate serde_json; use duniter_crypto::hashs::Hash; use duniter_crypto::keys::*; -use duniter_documents::blockchain::v10::documents::transaction::{ +use duniter_documents::v10::transaction::{ TransactionDocument, TransactionDocumentBuilder, TransactionInput, TransactionInputUnlocks, TransactionOutput, }; -use duniter_documents::blockchain::DocumentBuilder; use duniter_documents::Blockstamp; +use duniter_documents::DocumentBuilder; +use std::str::FromStr; pub fn parse_transaction( currency: &str, @@ -36,7 +37,7 @@ pub fn parse_transaction( let mut inputs = Vec::with_capacity(inputs_array.len()); for input in inputs_array { let input_str = input.as_str()?; - match TransactionInput::parse_from_str(input_str) { + match TransactionInput::from_str(input_str) { Ok(input) => inputs.push(input), Err(_) => { return None; @@ -46,7 +47,7 @@ pub fn parse_transaction( let unlocks_array = source.get("unlocks")?.as_array()?; let mut unlocks = Vec::with_capacity(unlocks_array.len()); for unlock in unlocks_array { - match TransactionInputUnlocks::parse_from_str(unlock.as_str()?) { + match TransactionInputUnlocks::from_str(unlock.as_str()?) { Ok(unlock) => unlocks.push(unlock), Err(_) => { return None; @@ -56,7 +57,7 @@ pub fn parse_transaction( let outputs_array = source.get("outputs")?.as_array()?; let mut outputs = Vec::with_capacity(outputs_array.len()); for output in outputs_array { - match TransactionOutput::parse_from_str(output.as_str()?) { + match TransactionOutput::from_str(output.as_str()?) { Ok(output) => outputs.push(output), Err(_) => { return None; @@ -121,15 +122,15 @@ Merci pour la calligraphie ;) de Liam$\ ed25519::PublicKey::from_base58("51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2") .unwrap(), )], - inputs: &vec![TransactionInput::parse_from_str( + inputs: &vec![TransactionInput::from_str( "1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496", ) .unwrap()], - outputs: &vec![TransactionOutput::parse_from_str( + outputs: &vec![TransactionOutput::from_str( "1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)", ) .unwrap()], - unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)").unwrap()], + unlocks: &vec![TransactionInputUnlocks::from_str("0:SIG(0)").unwrap()], comment: "Merci pour la calligraphie ;) de Liam", hash: None, };