Skip to content
Snippets Groups Projects

WIP: Resolve "DUBP local validation"

Closed jawaka requested to merge jawaka-146-dubp-local-validation into dev

Files

@@ -13,7 +13,7 @@
@@ -13,7 +13,7 @@
// You should have received a copy of the GNU Affero General Public License
// 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/>.
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Sub-module checking if a block complies with all the rules of the (DUBP DUniter Blockchain Protocol).
//! Sub-module that checks and applies the content of a block according to the DUBP (DUBP DUniter Blockchain Protocol).
pub mod hashs;
pub mod hashs;
@@ -25,12 +25,387 @@ use durs_blockchain_dal::*;
@@ -25,12 +25,387 @@ use durs_blockchain_dal::*;
use durs_wot::*;
use durs_wot::*;
use std::collections::HashMap;
use std::collections::HashMap;
 
use dubp_documents::documents::block::TxDocOrTxHash;
 
use dubp_documents::text_document_traits::CompactTextDocument;
 
use dubp_documents::VerificationResult;
 
use durs_common_tools::fatal_error;
 
 
pub static ZERO_STRING: &'static str = "0";
 
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Copy, Clone)]
pub enum InvalidBlockError {
pub enum InvalidBlockError {
NoPreviousBlock,
NoPreviousBlock,
VersionDecrease,
VersionDecrease,
}
}
 
#[derive(Debug, Clone)]
 
///
 
pub enum TransactionDocumentError {
 
// todo
 
LengthError, // too_short or too_large
 
NumberSourcesError, // ...Error uselesse
 
UnlocksError,
 
SignatureIssuerError,
 
VersionError,
 
SignatureCountError, // SIGError(SIGError) existe déjà
 
SignaturesOrderError,
 
SignatureConstructionError,
 
VerificationResult(VerificationResult),
 
}
 
 
/*
 
impl From<VerificationResult> for TransactionDocumentError {
 
fn from(err: VerificationResult) -> Self {
 
VerificationResult(err)
 
}
 
}
 
*/
 
 
// #[derive(Debug, Clone, Fail)]
 
#[derive(Debug, Clone)]
 
// todo : documenter variante et fail
 
/// Local verification of a block error
 
pub enum LocalVerifyBlockError {
 
// todo
 
VerifyBlockHashsError, // invalidHash (expected_hash, actual_hash), verifiy inner hash à changer
 
/// the block version was not in the expected versions
 
Version {
 
expected_version: Vec<usize>,
 
actual_version: u32,
 
},
 
LocalVerifyGenesisBlockError(LocalVerifyGenesisBlockError),
 
LocalVerifyNotGenesisBlockError(LocalVerifyNotGenesisBlockError),
 
 
BlockTimeError,
 
ZerosHashBlockError,
 
SignaturesLenBlockError, // supprimer
 
SignatureBlockError, // SIGError, faudra faire une vérif sur le nb d'issuer "too many issuers"
 
SignatureMembershipDocumentError,
 
SignatureRevocationDocumentError,
 
TextDocumentFormat,
 
//#[fail(display = "blabl {}", tx_post)]
 
TransactionDocumentError(TransactionDocumentError), // innerTx document error{tx_post : usize, error : TransactionDocumentError }
 
/* TransactionDocumentError {
 
/// Protocole version
 
tx_post : usize,
 
error : TransactionDocumentError,
 
} */
 
}
 
 
// from tuple usize regarder gitlab
 
impl From<LocalVerifyGenesisBlockError> for LocalVerifyBlockError {
 
fn from(err: LocalVerifyGenesisBlockError) -> Self {
 
LocalVerifyGenesisBlockError(err)
 
}
 
}
 
 
// from tuple usize regarder gitlab
 
impl From<LocalVerifyNotGenesisBlockError> for LocalVerifyBlockError {
 
fn from(err: LocalVerifyNotGenesisBlockError) -> Self {
 
LocalVerifyNotGenesisBlockError(err)
 
}
 
}
 
 
// from tuple usize regarder gitlab
 
impl From<TransactionDocumentError> for LocalVerifyBlockError {
 
fn from(err: TransactionDocumentError) -> Self {
 
TransactionDocumentError(err)
 
}
 
}
 
 
use crate::dubp::check::LocalVerifyBlockError::*;
 
use crate::dubp::check::LocalVerifyGenesisBlockError::*;
 
use crate::dubp::check::LocalVerifyNotGenesisBlockError::*;
 
use crate::dubp::check::TransactionDocumentError::*;
 
 
#[derive(Debug, Clone)]
 
/// Local verification error particular of a Genesis Block
 
pub enum LocalVerifyGenesisBlockError {
 
//NotGenesisBlock,
 
/// A previous hash is provided
 
UnexpectedPreviousHash,
 
/// A previous issuer is provided
 
UnexpectedPreviousIssuer,
 
/// No paramters are provided
 
MissingParameters,
 
/// No dividend is provided
 
MissingDividend,
 
/// Unit base is not zero
 
NonZeroUnitBase,
 
/// The block time is different from the median time
 
BlockTimeDifferentFromMedianTime,
 
}
 
 
pub fn local_verification_genesis_block(
 
block: &BlockDocument,
 
) -> Result<(), (LocalVerifyGenesisBlockError)> {
 
/*
 
if block.number.0 > 0 {
 
return Err(NotGenesisBlock);
 
}
 
*/
 
 
// Previous Hash
 
if block.previous_hash.is_some() {
 
return Err(UnexpectedPreviousHash);
 
}
 
 
// Previous issuer
 
if block.previous_issuer.is_some() {
 
return Err(UnexpectedPreviousIssuer);
 
}
 
 
// Parameters
 
if block.parameters.is_none() {
 
return Err(MissingParameters);
 
}
 
 
// Universal Dividend
 
if block.dividend.is_none() {
 
return Err(MissingDividend);
 
}
 
 
// UnitBase
 
if block.unit_base > 0 {
 
return Err(NonZeroUnitBase);
 
}
 
 
// Date
 
if block.time != block.median_time {
 
return Err(BlockTimeDifferentFromMedianTime);
 
}
 
 
return Ok(());
 
}
 
 
#[derive(Debug, Clone)]
 
/// Local verification error particular of a not-genesis Block
 
pub enum LocalVerifyNotGenesisBlockError {
 
/// No previous hash is provided
 
MissingPreviousHash,
 
/// No previous issuer is provided
 
MissingPreviousIssuer,
 
/// Some Paramters are provided
 
UnexpectedParameters,
 
}
 
 
/// Verification of local rules of a block which is supposed to be not-genesis
 
pub fn local_verification_not_genesis_block(
 
block: &BlockDocument,
 
) -> Result<(), LocalVerifyNotGenesisBlockError> {
 
// PreviousHash
 
if block.previous_hash.is_none() {
 
return Err(MissingPreviousHash);
 
}
 
 
// PreviousIssuer
 
if block.previous_issuer.is_none() {
 
return Err(MissingPreviousIssuer);
 
}
 
 
// Parameters
 
if block.parameters.is_some() {
 
return Err(UnexpectedParameters);
 
}
 
 
return Ok(());
 
}
 
 
pub fn local_verification(block: &BlockDocument) -> Result<(), LocalVerifyBlockError> {
 
if block.number.0 == 0 {
 
// Verify local rules for a genesis block
 
local_verification_genesis_block(block)?;
 
} else {
 
// Verify local rules for a not genesis block
 
local_verification_not_genesis_block(block)?;
 
}
 
 
// Version
 
if !(block.version == 10 || block.version == 11) {
 
return Err(Version {
 
expected_version: vec![10, 11],
 
actual_version: block.version,
 
});
 
}
 
 
// InnerHash
 
// todo : + compliqué car faut changer le retour de verify
 
if !block.verify_inner_hash() {
 
return Err(VerifyBlockHashsError);
 
}
 
 
// Nonce
 
// nothing to do
 
 
// Proof of work
 
if let Some(h) = block.hash {
 
let hash_string = h.0.to_hex();
 
let remainder = block.pow_min % 16;
 
let nb_zeros = (block.pow_min - remainder) / 16;
 
let repeated_zero_string = ZERO_STRING.repeat(nb_zeros);
 
if !hash_string.starts_with(&repeated_zero_string) {
 
return Err(ZerosHashBlockError); // plus explicite excpeted pattern 00000[0-3]* et le actual_hash format (hexa)
 
}
 
}
 
 
// Signature
 
if block.signatures.len() != 1 {
 
// optimisable en ne calculant pas toute la longueur du tableau ?
 
return Err(SignaturesLenBlockError);
 
}
 
 
match block.verify_signatures() {
 
VerificationResult::Valid() => (),
 
_ => return Err(SignatureBlockError),
 
} // récuperer les deux autres erreurs et renvoyer une SIG_error : invalid sig et
 
 
// Dates
 
//let avg_gen_time = block.parameters.avg_gen_time as f64;
 
//let maxGenTime = avg_gen_time * 1.189;
 
let max_acceleration = 1; // todo: max_acceleration = CEIL(maxGenTime * median_time_blocks) // rajouter currency parameters en argument Option utiliser unwrap!(option)
 
 
if block.time < block.median_time || block.median_time + max_acceleration < block.time {
 
return Err(BlockTimeError);
 
}
 
 
// Identities
 
for x in &block.identities {
 
match x.verify_signatures() {
 
VerificationResult::Valid() => (),
 
_ => return Err(SignatureBlockError),
 
}
 
}
 
 
// Memberships (Joiners, Actives, Leavers)
 
for x in &block.joiners {
 
match x.verify_signatures() {
 
VerificationResult::Valid() => (),
 
_ => return Err(SignatureMembershipDocumentError),
 
}
 
}
 
 
for x in &block.actives {
 
match x.verify_signatures() {
 
VerificationResult::Valid() => (),
 
_ => return Err(SignatureMembershipDocumentError),
 
}
 
}
 
 
for x in &block.leavers {
 
match x.verify_signatures() {
 
VerificationResult::Valid() => (),
 
_ => return Err(SignatureMembershipDocumentError),
 
}
 
}
 
 
// Revoked // pas une vérif locale en fait, erreur de conception
 
for x in &block.revoked {
 
match x {
 
dubp_documents::text_document_traits::TextDocumentFormat::Complete(y) => {
 
match y.verify_signatures() {
 
VerificationResult::Valid() => (),
 
_ => return Err(SignatureRevocationDocumentError),
 
} // deplacer dans compact // dans complete dire que c'est une erreur
 
}
 
dubp_documents::text_document_traits::TextDocumentFormat::Compact(y) => {
 
/*match y.verify_signatures() {
 
VerificationResult::Valid() => (),
 
_ => return Err(SignatureRevocationDocumentError),
 
}*/
 
// verify_signatures à implementer
 
}
 
_ => (), // compact n'existe pas // ne pas utiliser de _
 
}
 
}
 
 
// Transactions
 
for x in &block.transactions {
 
match x {
 
TxDocOrTxHash::TxDoc(y) => {
 
// A transaction in compact format cannot measure more than 100 lines
 
if y.as_compact_text().lines().count() >= 100 {
 
// question : c'est strict ?
 
return Err(TransactionDocumentError(LengthError));
 
}
 
// A transaction must have at least 1 source
 
if y.get_inputs().is_empty() {
 
return Err(TransactionDocumentError(NumberSourcesError));
 
}
 
// A transaction cannot have `SIG(INDEX)` unlocks with `INDEX >= ` issuers count. ??
 
/*if y.get_unlocks().len() >= y.issuers().len() {
 
return Err(TransactionDocumentError(SignatureIssuerError));
 
}*/
 
// A transaction's version must be equal to 10
 
if y.version() != 10 {
 
return Err(TransactionDocumentError(VersionError));
 
}
 
 
// Signatures count must be the same as issuers count
 
if y.signatures().len() != y.issuers().len() {
 
return Err(TransactionDocumentError(SignatureCountError));
 
}
 
 
/*
 
* A transaction **must** have signatures matching its content **for each issuer**
 
* Signatures are ordered by issuer
 
* Signatures are made over the transaction's content, signatures excepted
 
*/
 
let result = y.verify_signatures();
 
match result {
 
VerificationResult::Valid() => (),
 
_ => return Err(TransactionDocumentError(VerificationResult(result))),
 
} // invalid -> invalid SIG, incomplete : dans les transactions même paramètre, pour les autres il faut indiquer invlaid nb of signatures
 
}
 
TxDocOrTxHash::TxHash(y) => {
 
fatal_error!("Block contains a Transaction Hash (and not a Transaction Document)")
 
}
 
}
 
}
 
 
Ok(())
 
}
 
 
/*#[cfg(test)]
 
mod tests {
 
 
#[test]
 
fn generate_and_verify_block() {
 
let mut block = BlockDocument {
 
nonce: 0,
 
version: 10,
 
number: BlockNumber(107_984),
 
pow_min: 88,
 
time: 1_522_685_861,
 
median_time: 1522683184,
 
members_count: 896,
 
monetary_mass: 140_469_765,
 
unit_base: 0,
 
issuers_count: 42,
 
issuers_frame: 211,
 
issuers_frame_var: 0,
 
currency: CurrencyName(String::from("g1")),
 
issuers: vec![PubKey::Ed25519(ed25519::PublicKey::from_base58("DA4PYtXdvQqk1nCaprXH52iMsK5Ahxs1nRWbWKLhpVkQ").unwrap())],
 
signatures: vec![Sig::Ed25519(ed25519::Signature::from_base64("92id58VmkhgVNee4LDqBGSm8u/ooHzAD67JM6fhAE/CV8LCz7XrMF1DvRl+eRpmlaVkp6I+Iy8gmZ1WUM5C8BA==").unwrap())],
 
hash: None,
 
parameters: None,
 
previous_hash: Hash::from_hex("000001144968D0C3516BE6225E4662F182E28956AF46DD7FB228E3D0F9413FEB").expect("fail to parse previous_hash"),
 
previous_issuer: Some(PubKey::Ed25519(ed25519::PublicKey::from_base58("D3krfq6J9AmfpKnS3gQVYoy7NzGCc61vokteTS8LJ4YH").unwrap())),
 
inner_hash: None,
 
dividend: None,
 
identities: Vec::new(),
 
joiners: Vec::new(),
 
actives: Vec::new(),
 
leavers: Vec::new(),
 
revoked: Vec::new(),
 
excluded: Vec::new(),
 
certifications: vec![TextDocumentFormat::Complete(cert1)],
 
transactions: vec![TxDocOrTxHash::TxDoc(Box::new(tx1)), TxDocOrTxHash::TxDoc(Box::new(tx2))],
 
inner_hash_and_nonce_str: String::new(),
 
};
 
assert_eq!(local_verification(&block), Ok);
 
}
 
}*/
 
pub fn verify_block_validity<W: WebOfTrust>(
pub fn verify_block_validity<W: WebOfTrust>(
block: &BlockDocument,
block: &BlockDocument,
blockchain_db: &BinDB<LocalBlockchainV10Datas>,
blockchain_db: &BinDB<LocalBlockchainV10Datas>,
Loading