diff --git a/Cargo.lock b/Cargo.lock index 3cf30c0f68a..eabcc933c5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -769,7 +769,7 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "costs" version = "1.0.0" -source = "git+https://github.com/dashpay/grovedb?branch=develop#6748730f8ab4b6511a163972e8eb7b1568a8a19d" +source = "git+https://github.com/dashpay/grovedb?branch=develop#afd72c6b08b302be49179ffa2fdcc80f375027a6" dependencies = [ "integer-encoding", "intmap", @@ -1661,7 +1661,7 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "grovedb" version = "0.12.2" -source = "git+https://github.com/dashpay/grovedb?branch=develop#6748730f8ab4b6511a163972e8eb7b1568a8a19d" +source = "git+https://github.com/dashpay/grovedb?branch=develop#afd72c6b08b302be49179ffa2fdcc80f375027a6" dependencies = [ "bincode 1.3.3", "costs", @@ -2112,7 +2112,7 @@ dependencies = [ [[package]] name = "merk" version = "0.12.2" -source = "git+https://github.com/dashpay/grovedb?branch=develop#6748730f8ab4b6511a163972e8eb7b1568a8a19d" +source = "git+https://github.com/dashpay/grovedb?branch=develop#afd72c6b08b302be49179ffa2fdcc80f375027a6" dependencies = [ "blake3", "byteorder", @@ -3395,7 +3395,7 @@ dependencies = [ [[package]] name = "storage" version = "1.0.0" -source = "git+https://github.com/dashpay/grovedb?branch=develop#6748730f8ab4b6511a163972e8eb7b1568a8a19d" +source = "git+https://github.com/dashpay/grovedb?branch=develop#afd72c6b08b302be49179ffa2fdcc80f375027a6" dependencies = [ "blake3", "costs", @@ -3508,10 +3508,12 @@ dependencies = [ [[package]] name = "tenderdash-abci" -version = "0.12.0-dev.1" -source = "git+https://github.com/dashpay/rs-tenderdash-abci#623e225bee4bc4841bec9183b0710423359383d9" +version = "0.12.0-dev.2" +source = "git+https://github.com/dashpay/rs-tenderdash-abci?branch=fix/signatures#e1de2dcab2b38f242162e7e5a36cbc56582457d6" dependencies = [ "bytes", + "hex", + "lhash", "prost", "semver", "tenderdash-proto", @@ -3523,14 +3525,13 @@ dependencies = [ [[package]] name = "tenderdash-proto" -version = "0.12.0-dev.1" -source = "git+https://github.com/dashpay/rs-tenderdash-abci#623e225bee4bc4841bec9183b0710423359383d9" +version = "0.12.0-dev.2" +source = "git+https://github.com/dashpay/rs-tenderdash-abci?branch=fix/signatures#e1de2dcab2b38f242162e7e5a36cbc56582457d6" dependencies = [ "bytes", "chrono", "derive_more", "flex-error", - "lhash", "num-derive", "num-traits", "prost", @@ -3543,7 +3544,7 @@ dependencies = [ [[package]] name = "tenderdash-proto-compiler" version = "0.1.0" -source = "git+https://github.com/dashpay/rs-tenderdash-abci#623e225bee4bc4841bec9183b0710423359383d9" +source = "git+https://github.com/dashpay/rs-tenderdash-abci?branch=fix/signatures#e1de2dcab2b38f242162e7e5a36cbc56582457d6" dependencies = [ "fs_extra", "prost-build", @@ -3964,7 +3965,7 @@ checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314" [[package]] name = "visualize" version = "0.1.0" -source = "git+https://github.com/dashpay/grovedb?branch=develop#6748730f8ab4b6511a163972e8eb7b1568a8a19d" +source = "git+https://github.com/dashpay/grovedb?branch=develop#afd72c6b08b302be49179ffa2fdcc80f375027a6" dependencies = [ "hex", "itertools", diff --git a/packages/dashmate/configs/system/base.js b/packages/dashmate/configs/system/base.js index 1fab963ff88..cba2e490a08 100644 --- a/packages/dashmate/configs/system/base.js +++ b/packages/dashmate/configs/system/base.js @@ -143,7 +143,7 @@ module.exports = { }, tenderdash: { docker: { - image: 'dashpay/tenderdash:0.12.0-dev.2', + image: 'dashpay/tenderdash:fix-CoreChainLockedHeight', }, p2p: { port: 26656, diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index f28f8037165..c011709a1e5 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -43,7 +43,7 @@ tracing-subscriber = { version = "0.3.16", default-features = false, features = "ansi", ], optional = true } atty = { version = "0.2.14", optional = true } -tenderdash-abci = { git = "https://github.com/dashpay/rs-tenderdash-abci", optional = true } +tenderdash-abci = { git = "https://github.com/dashpay/rs-tenderdash-abci", branch = "fix/signatures", optional = true } # tenderdash-abci = { path = "../../../rs-tenderdash-abci/abci", optional = true } anyhow = { version = "1.0.70" } lazy_static = "1.4.0" diff --git a/packages/rs-drive-abci/src/abci/commit.rs b/packages/rs-drive-abci/src/abci/commit.rs index 876613afa9c..5aa4102e565 100644 --- a/packages/rs-drive-abci/src/abci/commit.rs +++ b/packages/rs-drive-abci/src/abci/commit.rs @@ -4,9 +4,10 @@ use crate::execution::finalize_block_cleaned_request::{CleanedBlockId, CleanedCo use dashcore_rpc::dashcore_rpc_json::QuorumType; use dpp::bls_signatures; use dpp::validation::{SimpleValidationResult, ValidationResult}; +use tenderdash_abci::proto; use tenderdash_abci::proto::abci::CommitInfo; use tenderdash_abci::proto::types::BlockId; -use tenderdash_abci::proto::{self, signatures::SignDigest}; +use tenderdash_abci::signatures::SignDigest; use super::AbciError; @@ -34,7 +35,8 @@ impl Commit { block_id: Some(block_id.try_into().expect("cannot convert block id")), height: height as i64, round: ci.round as i32, - quorum_hash: ci.quorum_hash.to_vec(), + // we need to "un-reverse" quorum hash, as it was reversed in [CleanedCommitInfo::try_from] + quorum_hash: ci.quorum_hash.iter().rev().cloned().collect(), threshold_block_signature: ci.block_signature.to_vec(), threshold_vote_extensions: ci.threshold_vote_extensions.to_vec(), }, @@ -94,16 +96,20 @@ impl Commit { //todo: maybe cache this to lower the chance of a hashing based attack (forcing the // same calculation each time) + let quorum_hash = &self.inner.quorum_hash[..] + .try_into() + .expect("invalid quorum hash length"); + let hash = match self .inner .sign_digest( &self.chain_id, self.quorum_type as u8, - &self.inner.quorum_hash, + quorum_hash, self.inner.height, self.inner.round, ) - .map_err(AbciError::TenderdashProto) + .map_err(AbciError::Tenderdash) { Ok(hash) => hash, Err(e) => return ValidationResult::new_with_error(e), @@ -128,10 +134,8 @@ mod test { dashcore::hashes::sha256, dashcore::hashes::Hash, dashcore_rpc_json::QuorumType, }; use dpp::bls_signatures::PublicKey; - use tenderdash_abci::proto::{ - signatures::{SignBytes, SignDigest}, - types::{BlockId, PartSetHeader, StateId}, - }; + use tenderdash_abci::proto::types::{BlockId, PartSetHeader, StateId}; + use tenderdash_abci::signatures::{SignBytes, SignDigest}; /// Given a commit info and a signature, check that the signature is verified correctly #[test] diff --git a/packages/rs-drive-abci/src/abci/handlers.rs b/packages/rs-drive-abci/src/abci/handlers.rs index c81ff95f609..d13f69535cc 100644 --- a/packages/rs-drive-abci/src/abci/handlers.rs +++ b/packages/rs-drive-abci/src/abci/handlers.rs @@ -33,7 +33,12 @@ //! use crate::abci::server::AbciApplication; +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::execution::block_proposal::BlockProposal; +use crate::execution::engine::BlockExecutionOutcome; use crate::rpc::core::CoreRPCLike; +use dashcore_rpc::dashcore::hashes::hex::ToHex; use dpp::errors::consensus::codes::ErrorWithCode; use drive::fee::credits::SignedCredits; use tenderdash_abci::proto::abci::response_verify_vote_extension::VerifyStatus; @@ -44,12 +49,7 @@ use tenderdash_abci::proto::abci::{ RequestProcessProposal, RequestQuery, ResponseCheckTx, ResponseFinalizeBlock, ResponseInitChain, ResponsePrepareProposal, ResponseProcessProposal, ResponseQuery, TxRecord, }; -use tenderdash_abci::proto::types::{CoreChainLock, VoteExtensionType}; - -use crate::error::execution::ExecutionError; -use crate::error::Error; -use crate::execution::block_proposal::BlockProposal; -use crate::execution::engine::BlockExecutionOutcome; +use tenderdash_abci::proto::types::VoteExtensionType; use super::withdrawal::WithdrawalTxs; use super::AbciError; @@ -261,10 +261,15 @@ where let block_state_info = &block_execution_context.block_state_info; - if !block_state_info.matches_current_block(height as u64, round as u32, block_hash)? { + if !block_state_info.matches_current_block( + height as u64, + round as u32, + block_hash.clone(), + )? { return Err(Error::from(AbciError::RequestForWrongBlockReceived(format!( - "received request for height: {} round: {}, expected height: {} round: {}", - height, round, block_state_info.height, block_state_info.round + "received request for height: {} round: {}, block: {}; expected height: {} round: {}, block: {}", + height, round, block_hash.to_hex(), + block_state_info.height, block_state_info.round, block_state_info.block_hash.to_hex() ))) .into()); } else { @@ -306,10 +311,15 @@ where let block_state_info = &block_execution_context.block_state_info; - if !block_state_info.matches_current_block(height as u64, round as u32, block_hash)? { + if !block_state_info.matches_current_block( + height as u64, + round as u32, + block_hash.clone(), + )? { return Err(Error::from(AbciError::RequestForWrongBlockReceived(format!( - "received request for height: {} round: {}, expected height: {} round: {}", - height, round, block_state_info.height, block_state_info.round + "received request for height: {} round: {}, block: {}; expected height: {} round: {}, block: {}", + height, round,block_hash.to_hex(), + block_state_info.height, block_state_info.round, block_state_info.block_hash.to_hex() ))) .into()); } diff --git a/packages/rs-drive-abci/src/abci/messages.rs b/packages/rs-drive-abci/src/abci/messages.rs index b9a0514106f..af21d0e0536 100644 --- a/packages/rs-drive-abci/src/abci/messages.rs +++ b/packages/rs-drive-abci/src/abci/messages.rs @@ -45,22 +45,47 @@ use drive::fee::result::FeeResult; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use tenderdash_abci::proto::abci::RequestInitChain; use tenderdash_abci::proto::google::protobuf::Timestamp; +use tenderdash_abci::proto::serializers::timestamp::ToMilis; + +use super::AbciError; /// A struct for handling chain initialization requests #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct InitChainRequest { /// The genesis time in milliseconds - pub genesis_time_ms: TimestampMillis, - /// The system identity public keys - pub system_identity_public_keys: SystemIdentityPublicKeys, + pub genesis_time: TimestampMillis, + + /// Initial core chain lock height. + pub initial_core_height: Option, +} + +impl TryFrom for InitChainRequest { + type Error = AbciError; + fn try_from(request: RequestInitChain) -> Result { + let genesis_time = request + .time + .ok_or(AbciError::BadRequest( + "genesis time is required in init chain".to_string(), + ))? + .to_milis() as TimestampMillis; + let initial_core_height = match request.initial_core_height { + 0 => None, + h => Some(h), + }; + + Ok(Self { + genesis_time, + initial_core_height, + }) + } } impl From for RequestInitChain { fn from(value: InitChainRequest) -> Self { let InitChainRequest { - genesis_time_ms, - system_identity_public_keys: _, + genesis_time: genesis_time_ms, + initial_core_height, } = value; RequestInitChain { time: Some(Timestamp { @@ -72,7 +97,7 @@ impl From for RequestInitChain { validator_set: None, app_state_bytes: vec![], initial_height: 0, - initial_core_height: 0, + initial_core_height: initial_core_height.unwrap_or_default(), } } } diff --git a/packages/rs-drive-abci/src/abci/mimic.rs b/packages/rs-drive-abci/src/abci/mimic.rs index 49fda706de4..a574b914086 100644 --- a/packages/rs-drive-abci/src/abci/mimic.rs +++ b/packages/rs-drive-abci/src/abci/mimic.rs @@ -25,10 +25,10 @@ use tenderdash_abci::proto::google::protobuf::Timestamp; use tenderdash_abci::proto::types::{ Block, BlockId, Data, EvidenceList, Header, PartSetHeader, VoteExtension, VoteExtensionType, }; -use tenderdash_abci::proto::version::Consensus; use tenderdash_abci::{ - proto::{self, signatures::SignDigest}, - Application, + signatures::SignDigest, + proto::{self, version::Consensus}, + Application }; /// The outcome struct when mimicking block execution @@ -243,11 +243,12 @@ impl<'a, C: CoreRPCLike> AbciApplication<'a, C> { //if not in testing this will default to true if self.platform.config.testing_configs.block_signing { + let quorum_hash:[u8;32] = current_quorum.quorum_hash[..].try_into().expect("wrong quorum hash len"); let digest = commit .sign_digest( &chain_id, quorum_type as u8, - ¤t_quorum.quorum_hash, + &quorum_hash, height as i64, 0, ) diff --git a/packages/rs-drive-abci/src/abci/withdrawal.rs b/packages/rs-drive-abci/src/abci/withdrawal.rs index d7a5874b563..e353a7feaec 100644 --- a/packages/rs-drive-abci/src/abci/withdrawal.rs +++ b/packages/rs-drive-abci/src/abci/withdrawal.rs @@ -12,9 +12,9 @@ use drive::{ use std::fmt::Display; use tenderdash_abci::proto::{ abci::ExtendVoteExtension, - signatures::SignDigest, types::{VoteExtension, VoteExtensionType}, }; +use tenderdash_abci::signatures::SignDigest; use super::AbciError; @@ -130,14 +130,12 @@ impl<'a> WithdrawalTxs<'a> { let hash = match s.sign_digest( chain_id, quorum_type as u8, - quorum_hash, + quorum_hash.try_into().expect("invalid quorum hash length"), height as i64, round as i32, ) { Ok(h) => h, - Err(e) => { - return SimpleValidationResult::new_with_error(AbciError::TenderdashProto(e)) - } + Err(e) => return SimpleValidationResult::new_with_error(AbciError::Tenderdash(e)), }; let signature = match bls_signatures::Signature::from_bytes(&s.signature) { diff --git a/packages/rs-drive-abci/src/block.rs b/packages/rs-drive-abci/src/block.rs index e908b6f8ef9..40e023db0ba 100644 --- a/packages/rs-drive-abci/src/block.rs +++ b/packages/rs-drive-abci/src/block.rs @@ -32,13 +32,14 @@ use crate::error::Error; use crate::execution::block_proposal::BlockProposal; use crate::execution::fee_pools::epoch::EpochInfo; use crate::state::PlatformState; +use dashcore_rpc::dashcore::hashes::hex::ToHex; use dashcore_rpc::dashcore::Txid; use dpp::block::block_info::BlockInfo; use dpp::block::epoch::Epoch; - use std::collections::BTreeMap; /// Block info +#[derive(Debug)] pub struct BlockStateInfo { /// Block height pub height: u64, @@ -54,8 +55,8 @@ pub struct BlockStateInfo { pub core_chain_locked_height: u32, /// Block hash pub block_hash: [u8; 32], - /// Block commit hash after processing - pub commit_hash: Option<[u8; 32]>, + /// Application hash + pub app_hash: Option<[u8; 32]>, } impl BlockStateInfo { @@ -81,7 +82,7 @@ impl BlockStateInfo { proposer_pro_tx_hash: proposal.proposer_pro_tx_hash, core_chain_locked_height: proposal.core_chain_locked_height, block_hash: proposal.block_hash.unwrap_or_default(), // we will set it later - commit_hash: None, + app_hash: None, } } @@ -126,7 +127,20 @@ impl BlockStateInfo { )) })?; // the order is important here, don't verify commit hash before height and round - Ok(self.height == height && self.round == round && self.core_chain_locked_height == core_block_height && self.proposer_pro_tx_hash == proposer_pro_tx_hash && self.commit_hash.ok_or(Error::Abci(AbciError::FinalizeBlockReceivedBeforeProcessing(format!("we received a block with hash {}, but don't have a current block being processed", hex::encode(received_hash)))))? == received_hash) + tracing::trace!( + self=?self, + ?height, + ?round, + ?core_block_height, + proposer_pro_tx_hash = proposer_pro_tx_hash.to_hex(), + commit_hash = received_hash.to_hex(), + "check if block info matches request" + ); + Ok(self.height == height + && self.round == round + && self.core_chain_locked_height == core_block_height + && self.proposer_pro_tx_hash == proposer_pro_tx_hash + && self.block_hash == received_hash) } } /// Block execution context diff --git a/packages/rs-drive-abci/src/error/execution.rs b/packages/rs-drive-abci/src/error/execution.rs index 32f61c4ee36..70a272d8401 100644 --- a/packages/rs-drive-abci/src/error/execution.rs +++ b/packages/rs-drive-abci/src/error/execution.rs @@ -33,6 +33,17 @@ pub enum ExecutionError { #[error("initialization fork not active: {0}")] InitializationForkNotActive(String), + /// Invalid core chain locked height + #[error("core chain locked height {requested} is invalid: {v20_fork} <= {requested} <= {best} is not true")] + InitializationBadCoreLockedHeight { + /// v20 fork height + v20_fork: u32, + /// requested core height + requested: u32, + /// best core lock height + best: u32, + }, + /// An error occurred during initialization. #[error("initialization error: {0}")] InitializationError(&'static str), diff --git a/packages/rs-drive-abci/src/execution/data_trigger/reward_share_data_triggers/mod.rs b/packages/rs-drive-abci/src/execution/data_trigger/reward_share_data_triggers/mod.rs index f2b97a607eb..423c9009072 100644 --- a/packages/rs-drive-abci/src/execution/data_trigger/reward_share_data_triggers/mod.rs +++ b/packages/rs-drive-abci/src/execution/data_trigger/reward_share_data_triggers/mod.rs @@ -175,7 +175,7 @@ mod test { use crate::state::PlatformState; use crate::test::helpers::setup::TestPlatformBuilder; use dashcore_rpc::dashcore::hashes::Hash; - use dashcore_rpc::dashcore::ProTxHash; + use dashcore_rpc::dashcore::{ProTxHash, Txid}; use dashcore_rpc::dashcore_rpc_json::{DMNState, MasternodeListItem, MasternodeType}; use dpp::block::block_info::BlockInfo; use dpp::data_contract::document_type::random_document::CreateRandomDocument; diff --git a/packages/rs-drive-abci/src/execution/engine.rs b/packages/rs-drive-abci/src/execution/engine.rs index ec7c4ed9e3e..b5004300da9 100644 --- a/packages/rs-drive-abci/src/execution/engine.rs +++ b/packages/rs-drive-abci/src/execution/engine.rs @@ -1,9 +1,8 @@ -use dashcore_rpc::dashcore::hashes::Hash; +use dashcore_rpc::dashcore::hashes::{hex::ToHex, Hash}; use dashcore_rpc::dashcore::{QuorumHash, Txid}; -use dpp::bls_signatures; - use dpp::block::block_info::BlockInfo; use dpp::block::epoch::Epoch; +use dpp::bls_signatures; use dpp::consensus::ConsensusError; use dpp::state_transition::StateTransition; use dpp::validation::{ @@ -381,7 +380,7 @@ where .unwrap() .map_err(|e| Error::Drive(GroveDB(e)))?; //GroveDb errors are system errors - block_execution_context.block_state_info.commit_hash = Some(root_hash); + block_execution_context.block_state_info.app_hash = Some(root_hash); let state = self.state.read().unwrap(); let validator_set_update = @@ -678,18 +677,20 @@ where )? { // we are on the wrong height or round validation_result.add_error(AbciError::WrongFinalizeBlockReceived(format!( - "received a block for h: {} r: {} c-h: {}, expected h: {} r: {} c-h: {}", + "received a block for h: {} r: {}, hash: {}, core height: {}, expected h: {} r: {}, hash: {}, core height: {}", height, round, + hash.to_hex(), block_header.core_chain_locked_height, block_state_info.height, block_state_info.round, + block_state_info.block_hash.to_hex(), block_state_info.core_chain_locked_height ))); return Ok(validation_result.into()); } - let mut state_cache = self.state.read().unwrap(); + let state_cache = self.state.read().unwrap(); if state_cache.current_validator_set_quorum_hash.as_inner() != &commit_info.quorum_hash { validation_result.add_error(AbciError::WrongFinalizeBlockReceived(format!( "received a block for h: {} r: {} with validator set quorum hash {} expected current validator set quorum hash is {}", diff --git a/packages/rs-drive-abci/src/execution/fee_pools/process_block_fees.rs b/packages/rs-drive-abci/src/execution/fee_pools/process_block_fees.rs index 54ee60f7615..9939bb5ebf7 100644 --- a/packages/rs-drive-abci/src/execution/fee_pools/process_block_fees.rs +++ b/packages/rs-drive-abci/src/execution/fee_pools/process_block_fees.rs @@ -318,7 +318,7 @@ mod tests { proposer_pro_tx_hash, core_chain_locked_height: 1, block_hash, - commit_hash: None, + app_hash: None, }; let epoch_info = @@ -500,7 +500,7 @@ mod tests { proposer_pro_tx_hash, core_chain_locked_height: 1, block_hash: [0; 32], - commit_hash: None, + app_hash: None, }; let epoch_info = diff --git a/packages/rs-drive-abci/src/execution/finalize_block_cleaned_request.rs b/packages/rs-drive-abci/src/execution/finalize_block_cleaned_request.rs index ee2bc9ce0a0..5c897857838 100644 --- a/packages/rs-drive-abci/src/execution/finalize_block_cleaned_request.rs +++ b/packages/rs-drive-abci/src/execution/finalize_block_cleaned_request.rs @@ -38,13 +38,14 @@ impl TryFrom for CleanedCommitInfo { ))); } - let quorum_hash = quorum_hash.try_into().map_err(|_| { + let mut quorum_hash: [u8; 32] = quorum_hash.try_into().map_err(|_| { Error::Abci(AbciError::BadRequestDataSize( "commit info quorum hash is not 32 bytes long".to_string(), )) })?; + quorum_hash.reverse(); - let block_signature = block_signature.try_into().map_err(|_| { + let block_signature: [u8; 96] = block_signature.try_into().map_err(|_| { Error::Abci(AbciError::BadRequestDataSize( "commit info block signature is not 96 bytes long".to_string(), )) @@ -275,17 +276,19 @@ impl TryFrom for CleanedBlockId { part_set_header, state_id, } = value; - let hash = hash.try_into().map_err(|_| { + let hash = hash_or_default(hash).map_err(|_| { Error::Abci(AbciError::BadRequestDataSize( "hash is not 32 bytes long in block id".to_string(), )) })?; + let Some(part_set_header) = part_set_header else { return Err(AbciError::BadRequest( "block id is missing part set header".to_string(), ).into()); }; - let state_id = state_id.try_into().map_err(|_| { + + let state_id = hash_or_default(state_id).map_err(|_| { Error::Abci(AbciError::BadRequestDataSize( "state id is not 32 bytes long".to_string(), )) @@ -448,3 +451,12 @@ impl TryFrom for FinalizeBlockCleanedRequest { }) } } + +fn hash_or_default(hash: Vec) -> Result<[u8; 32], as TryInto<[u8; 32]>>::Error> { + if hash.is_empty() { + // hash is empty at genesis, we assume it is zeros + Ok([0u8; 32]) + } else { + hash.try_into() + } +} diff --git a/packages/rs-drive-abci/src/execution/initialization.rs b/packages/rs-drive-abci/src/execution/initialization.rs index 6b3757b0230..ff18713ecc4 100644 --- a/packages/rs-drive-abci/src/execution/initialization.rs +++ b/packages/rs-drive-abci/src/execution/initialization.rs @@ -1,18 +1,15 @@ +use crate::abci::messages::InitChainRequest; use crate::error::execution::ExecutionError; use crate::error::Error; use crate::platform::Platform; use crate::rpc::core::CoreRPCLike; use crate::state::PlatformInitializationState; -use dashcore_rpc::dashcore_rpc_json::{ - Bip9SoftforkInfo, Bip9SoftforkStatus, GetChainTipsResultStatus, -}; +use dashcore_rpc::dashcore_rpc_json::Bip9SoftforkStatus; use dpp::block::block_info::BlockInfo; -use dpp::identity::TimestampMillis; use drive::error::Error::GroveDB; use drive::grovedb::Transaction; use tenderdash_abci::proto::abci::{RequestInitChain, ResponseInitChain, ValidatorSetUpdate}; -use tenderdash_abci::proto::serializers::timestamp::ToMilis; impl Platform where @@ -24,28 +21,11 @@ where request: RequestInitChain, transaction: &Transaction, ) -> Result { - // We receive the activation height, if core is not yet at this height + let request = InitChainRequest::try_from(request)?; + // We get core height early, as this also verifies v20 fork + let core_height = self.initial_core_height(request.initial_core_height)?; - let fork_info = self.core_rpc.get_fork_info("v20")?.ok_or( - ExecutionError::InitializationForkNotActive("fork is not yet known".to_string()), - )?; - if fork_info.status != Bip9SoftforkStatus::Active { - // fork is not good yet - return Err(ExecutionError::InitializationForkNotActive(format!( - "fork is not yet known (currently {:?})", - fork_info.status - )) - .into()); - } else { - tracing::debug!(?fork_info, "core fork v20 is active"); - }; - - let genesis_time = request - .time - .ok_or(Error::Execution(ExecutionError::InitializationError( - "genesis time is required in init chain", - )))? - .to_milis() as TimestampMillis; + let genesis_time = request.genesis_time; self.create_genesis_state( genesis_time, @@ -55,7 +35,6 @@ where let mut state_cache = self.state.write().unwrap(); - let core_height = self.initial_core_height(request.initial_core_height, &fork_info)?; self.update_core_info( &mut state_cache, core_height, @@ -98,20 +77,59 @@ where /// Determine initial core height. /// - /// TODO: rewrite this, it is non-deterministic - /// We use either core height received from Tenderdash (from genesis file), OR the current tip of active core chain. - /// We use current tip as default because we need a fully functional, up-to-date validator set. - fn initial_core_height( - &self, - requested: u32, - fork_info: &Bip9SoftforkInfo, - ) -> Result { - let core_height = if requested != 0 { - requested + /// Use core height received from Tenderdash (from genesis.json) by default, + /// otherwise we go with height of v20 fork. + /// + /// Core height is verified to ensure that it is both at or after v20 fork, and + /// before or at last chain lock. + /// + /// ## Error handling + /// + /// This function will fail if: + /// + /// * v20 fork is not yet active + /// * `requested` core height is before v20 fork + /// * `requested` core height is after current best chain lock + /// + fn initial_core_height(&self, requested: Option) -> Result { + let fork_info = self.core_rpc.get_fork_info("v20")?.ok_or( + ExecutionError::InitializationForkNotActive("fork is not yet known".to_string()), + )?; + if fork_info.status != Bip9SoftforkStatus::Active { + // fork is not good yet + return Err(ExecutionError::InitializationForkNotActive(format!( + "fork is not yet known (currently {:?})", + fork_info.status + )) + .into()); } else { - fork_info.since + tracing::debug!(?fork_info, "core fork v20 is active"); }; + let v20_fork = fork_info.since; - Ok(core_height) + tracing::trace!(requested, v20_fork, "selecting initial core lock height"); + + if let Some(requested) = requested { + let best = self.core_rpc.get_best_chain_lock()?.core_block_height; + // TODO in my opinion, the condition should be: + // + // `v20_fork <= requested && requested <= best` + // + // but it results in 1440 <= 1243 <= 1545 + // + // So, fork_info.since differs? is it non-deterministic? + if requested <= best { + Ok(requested) + } else { + Err(ExecutionError::InitializationBadCoreLockedHeight { + requested, + best, + v20_fork, + } + .into()) + } + } else { + Ok(v20_fork) + } } } diff --git a/packages/rs-drive-abci/src/identity_credit_withdrawal/mod.rs b/packages/rs-drive-abci/src/identity_credit_withdrawal/mod.rs index fc59b63a5a4..32230cbea46 100644 --- a/packages/rs-drive-abci/src/identity_credit_withdrawal/mod.rs +++ b/packages/rs-drive-abci/src/identity_credit_withdrawal/mod.rs @@ -640,7 +640,7 @@ mod tests { ], core_chain_locked_height: 96, block_hash: [0; 32], - commit_hash: None, + app_hash: None, }, epoch_info: EpochInfo { current_epoch_index: 1, @@ -807,7 +807,7 @@ mod tests { ], core_chain_locked_height: 96, block_hash: [0; 32], - commit_hash: None, + app_hash: None, }, epoch_info: EpochInfo { current_epoch_index: 1, @@ -991,7 +991,6 @@ mod tests { mod build_withdrawal_transactions_from_documents { use dpp::block::block_info::BlockInfo; - use dpp::document::Document; use dpp::identity::core_script::CoreScript; use dpp::identity::state_transition::identity_credit_withdrawal_transition::Pooling; use dpp::platform_value::platform_value; diff --git a/packages/rs-drive-abci/src/main.rs b/packages/rs-drive-abci/src/main.rs index 502309732e0..6aac57cc5b0 100644 --- a/packages/rs-drive-abci/src/main.rs +++ b/packages/rs-drive-abci/src/main.rs @@ -40,6 +40,10 @@ struct Cli { /// #[arg(short, long, action = clap::ArgAction::Count)] verbose: u8, + + /// Display colorful logs + #[arg(long)] + color: Option, } #[derive(Debug, Subcommand)] @@ -126,7 +130,8 @@ fn configure_logging(cli: &Cli) { _ => panic!("max verbosity level is 5"), }; - let layer = fmt::layer().with_ansi(atty::is(atty::Stream::Stdout)); + let ansi = cli.color.unwrap_or(atty::is(atty::Stream::Stdout)); + let layer = fmt::layer().with_ansi(ansi); registry().with(layer).with(env_filter).init(); diff --git a/packages/rs-drive-abci/tests/strategy_tests/main.rs b/packages/rs-drive-abci/tests/strategy_tests/main.rs index 8b3a476556e..8b45e8e5781 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/main.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/main.rs @@ -33,11 +33,10 @@ extern crate core; use anyhow::anyhow; -use dashcore_rpc::dashcore::{signer, Network, PrivateKey, ProTxHash, QuorumHash}; +use dashcore_rpc::dashcore::{signer, Network, PrivateKey, ProTxHash, QuorumHash, Txid}; use dashcore_rpc::dashcore_rpc_json::{ - Bip9SoftforkInfo, Bip9SoftforkStatus, DMNState, ExtendedQuorumDetails, - MasternodeListDiffWithMasternodes, MasternodeListItem, MasternodeType, QuorumInfoResult, - QuorumType, + Bip9SoftforkInfo, Bip9SoftforkStatus, DMNState, ExtendedQuorumDetails, MasternodeListItem, + MasternodeType, QuorumInfoResult, QuorumType, }; use dpp::bls_signatures::PrivateKey as BlsPrivateKey; use dpp::data_contract::state_transition::data_contract_create_transition::DataContractCreateTransition; @@ -1005,7 +1004,7 @@ pub struct ChainExecutionOutcome<'a> { pub end_epoch_index: u16, pub end_time_ms: u64, pub strategy: Strategy, - pub withdrawals: Vec, + pub withdrawals: Vec, } pub struct ChainExecutionParameters { diff --git a/packages/rs-drive-verify-c-binding/src/lib.rs b/packages/rs-drive-verify-c-binding/src/lib.rs index 047b90961cc..7e62d776a93 100644 --- a/packages/rs-drive-verify-c-binding/src/lib.rs +++ b/packages/rs-drive-verify-c-binding/src/lib.rs @@ -8,7 +8,7 @@ use crate::types::{ PublicKeyHashIdentityMap, }; use crate::util::{build_c_identity_struct, extract_vector_from_pointer, vec_to_pointer}; -use drive::drive::verify::AssetLockProof as DppAssetLockProof; +use drive::dpp::identity::state_transition::asset_lock_proof::AssetLockProof as DppAssetLockProof; use drive::drive::verify::Identity as DppIdentity; use drive::drive::Drive; use std::collections::BTreeMap; diff --git a/packages/rs-drive/src/drive/verify/mod.rs b/packages/rs-drive/src/drive/verify/mod.rs index e2084ed5186..44749bf1de5 100644 --- a/packages/rs-drive/src/drive/verify/mod.rs +++ b/packages/rs-drive/src/drive/verify/mod.rs @@ -6,11 +6,10 @@ use crate::drive::{unique_key_hashes_tree_path_vec, Drive}; use crate::error::proof::ProofError; use crate::error::Error; +use crate::fee::credits::Credits; use dpp::identifier::Identifier; use dpp::identity::{IdentityPublicKey, KeyID}; -pub use dpp::prelude::{AssetLockProof, Identity, Revision}; - -use crate::fee::credits::Credits; +pub use dpp::prelude::{Identity, Revision}; use dpp::serialization_traits::PlatformDeserializable; use grovedb::GroveDb; use std::collections::BTreeMap;