Skip to content

Commit

Permalink
fix(drive): inconsistent platform state and version during ABCI calls (
Browse files Browse the repository at this point in the history
  • Loading branch information
shumkov authored Mar 8, 2024
1 parent 4129cf7 commit 22137c7
Show file tree
Hide file tree
Showing 96 changed files with 1,085 additions and 975 deletions.
1 change: 1 addition & 0 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/dashmate/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"ajv-formats": "^2.1.1",
"awilix": "^4.2.6",
"begoo": "^2.0.2",
"bs58": "^4.0.1",
"chalk": "^4.1.0",
"cron": "^2.1.0",
"dockerode": "^3.3.5",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import DAPIClient from '@dashevo/dapi-client';
import bs58 from 'bs58';
import { Listr } from 'listr2';
import WithdrawalsContract from '@dashevo/withdrawals-contract/lib/systemIds.js';
import wait from '../../../util/wait.js';

/**
Expand Down Expand Up @@ -31,12 +33,16 @@ export default function waitForNodeToBeReadyTaskFactory() {
},
});

const withdrawalsContractId = bs58.decode(WithdrawalsContract.contractId);

let success = false;
do {
const response = await dapiClient.platform.getEpochsInfo(0, 1, {
const response = await dapiClient.platform.getDataContract(withdrawalsContractId, {
retries: 0,
prove: false,
})
.catch(() => {});
.catch(() => {
});

success = Boolean(response);

Expand Down
2 changes: 1 addition & 1 deletion packages/rs-drive-abci/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ rust-version = "1.76"
license = "MIT"

[dependencies]
arc-swap = "1.7.0"
bincode = { version = "2.0.0-rc.3", features = ["serde"] }
ciborium = { git = "https://github.com/qrayven/ciborium", branch = "feat-ser-null-as-undefined" }
chrono = "0.4.20"
Expand All @@ -29,7 +30,6 @@ drive = { path = "../rs-drive", default-features = false, features = [
thiserror = "1.0.30"
rand = "0.8.5"
tempfile = "3.3.0"
parking_lot = "0.12.1"
hex = "0.4.3"
indexmap = { version = "1.9.3", features = ["serde"] }
sha2 = "0.10.6"
Expand Down
22 changes: 16 additions & 6 deletions packages/rs-drive-abci/src/abci/app/consensus.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use crate::abci::app::{PlatformApplication, TransactionalApplication};
use crate::abci::app::{BlockExecutionApplication, PlatformApplication, TransactionalApplication};
use crate::abci::handler;
use crate::abci::handler::error::error_into_exception;
use crate::error::execution::ExecutionError;
use crate::error::Error;
use crate::execution::types::block_execution_context::BlockExecutionContext;
use crate::platform_types::platform::Platform;
use crate::rpc::core::CoreRPCLike;
use dpp::version::PlatformVersion;
use drive::grovedb::Transaction;
use std::cell::{Ref, RefCell, RefMut};
use std::fmt::Debug;
use std::sync::RwLock;
use tenderdash_abci::proto::abci as proto;
Expand All @@ -17,16 +20,19 @@ use tenderdash_abci::proto::abci as proto;
pub struct ConsensusAbciApplication<'a, C> {
/// Platform
platform: &'a Platform<C>,
/// The current transaction
/// The current GroveDb transaction
transaction: RwLock<Option<Transaction<'a>>>,
/// The current block execution context
block_execution_context: RwLock<Option<BlockExecutionContext>>,
}

impl<'a, C> ConsensusAbciApplication<'a, C> {
/// Create new ABCI app
pub fn new(platform: &'a Platform<C>) -> Self {
Self {
platform,
transaction: RwLock::new(None),
transaction: Default::default(),
block_execution_context: Default::default(),
}
}
}
Expand All @@ -37,6 +43,12 @@ impl<'a, C> PlatformApplication<C> for ConsensusAbciApplication<'a, C> {
}
}

impl<'a, C> BlockExecutionApplication for ConsensusAbciApplication<'a, C> {
fn block_execution_context(&self) -> &RwLock<Option<BlockExecutionContext>> {
&self.block_execution_context
}
}

impl<'a, C> TransactionalApplication<'a> for ConsensusAbciApplication<'a, C> {
/// create and store a new transaction
fn start_transaction(&self) {
Expand All @@ -49,7 +61,7 @@ impl<'a, C> TransactionalApplication<'a> for ConsensusAbciApplication<'a, C> {
}

/// Commit a transaction
fn commit_transaction(&self) -> Result<(), Error> {
fn commit_transaction(&self, platform_version: &PlatformVersion) -> Result<(), Error> {
let transaction = self
.transaction
.write()
Expand All @@ -59,8 +71,6 @@ impl<'a, C> TransactionalApplication<'a> for ConsensusAbciApplication<'a, C> {
"trying to commit a transaction, but we are not in one",
)))?;

let platform_state = self.platform.state.read();
let platform_version = platform_state.current_platform_version()?;
self.platform
.drive
.commit_transaction(transaction, &platform_version.drive)
Expand Down
22 changes: 16 additions & 6 deletions packages/rs-drive-abci/src/abci/app/full.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::abci::app::{PlatformApplication, TransactionalApplication};
use crate::abci::app::{BlockExecutionApplication, PlatformApplication, TransactionalApplication};
use crate::abci::handler;
use crate::abci::handler::error::error_into_exception;
use crate::error::execution::ExecutionError;
use crate::error::Error;
use crate::execution::types::block_execution_context::BlockExecutionContext;
use crate::platform_types::platform::Platform;
use crate::rpc::core::CoreRPCLike;
use dpp::version::PlatformVersion;
use drive::grovedb::Transaction;
use std::fmt::Debug;
use std::sync::RwLock;
Expand All @@ -17,16 +19,19 @@ use tenderdash_abci::proto::abci as proto;
pub struct FullAbciApplication<'a, C> {
/// Platform
pub platform: &'a Platform<C>,
/// The current transaction
/// The current GroveDB transaction
pub transaction: RwLock<Option<Transaction<'a>>>,
/// The current block execution context
pub block_execution_context: RwLock<Option<BlockExecutionContext>>,
}

impl<'a, C> FullAbciApplication<'a, C> {
/// Create new ABCI app
pub fn new(platform: &'a Platform<C>) -> Self {
Self {
platform,
transaction: RwLock::new(None),
transaction: Default::default(),
block_execution_context: Default::default(),
}
}
}
Expand All @@ -37,6 +42,12 @@ impl<'a, C> PlatformApplication<C> for FullAbciApplication<'a, C> {
}
}

impl<'a, C> BlockExecutionApplication for FullAbciApplication<'a, C> {
fn block_execution_context(&self) -> &RwLock<Option<BlockExecutionContext>> {
&self.block_execution_context
}
}

impl<'a, C> TransactionalApplication<'a> for FullAbciApplication<'a, C> {
/// create and store a new transaction
fn start_transaction(&self) {
Expand All @@ -49,7 +60,7 @@ impl<'a, C> TransactionalApplication<'a> for FullAbciApplication<'a, C> {
}

/// Commit a transaction
fn commit_transaction(&self) -> Result<(), Error> {
fn commit_transaction(&self, platform_version: &PlatformVersion) -> Result<(), Error> {
let transaction = self
.transaction
.write()
Expand All @@ -58,8 +69,7 @@ impl<'a, C> TransactionalApplication<'a> for FullAbciApplication<'a, C> {
.ok_or(Error::Execution(ExecutionError::NotInTransaction(
"trying to commit a transaction, but we are not in one",
)))?;
let platform_state = self.platform.state.read();
let platform_version = platform_state.current_platform_version()?;

self.platform
.drive
.commit_transaction(transaction, &platform_version.drive)
Expand Down
10 changes: 9 additions & 1 deletion packages/rs-drive-abci/src/abci/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ mod consensus;
pub mod execution_result;
mod full;

use crate::execution::types::block_execution_context::BlockExecutionContext;
use crate::rpc::core::DefaultCoreRPC;
pub use check_tx::CheckTxAbciApplication;
pub use consensus::ConsensusAbciApplication;
use dpp::version::PlatformVersion;
pub use full::FullAbciApplication;

/// Platform-based ABCI application
Expand All @@ -29,5 +31,11 @@ pub trait TransactionalApplication<'a> {
fn transaction(&self) -> &RwLock<Option<Transaction<'a>>>;

/// Commits created transaction
fn commit_transaction(&self) -> Result<(), Error>;
fn commit_transaction(&self, platform_version: &PlatformVersion) -> Result<(), Error>;
}

/// Application that executes blocks and need to keep context between handlers
pub trait BlockExecutionApplication {
/// Returns the current block execution context
fn block_execution_context(&self) -> &RwLock<Option<BlockExecutionContext>>;
}
10 changes: 7 additions & 3 deletions packages/rs-drive-abci/src/abci/handler/check_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ where
{
let _timer = crate::metrics::abci_request_duration("check_tx");

let platform_state = platform.state.read();
let platform_state = platform.state.load();
let platform_version = platform_state.current_platform_version()?;
drop(platform_state);

let proto::RequestCheckTx { tx, r#type } = request;
match platform.check_tx(tx.as_slice(), r#type.try_into()?, platform_version) {
match platform.check_tx(
tx.as_slice(),
r#type.try_into()?,
&platform_state,
platform_version,
) {
Ok(validation_result) => {
let first_consensus_error = validation_result.errors.first();

Expand Down
13 changes: 6 additions & 7 deletions packages/rs-drive-abci/src/abci/handler/extend_vote.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::abci::app::{PlatformApplication, TransactionalApplication};
use crate::abci::app::{BlockExecutionApplication, PlatformApplication, TransactionalApplication};
use crate::abci::AbciError;
use crate::error::execution::ExecutionError;
use crate::error::Error;
Expand All @@ -14,7 +14,7 @@ pub fn extend_vote<'a, A, C>(
request: proto::RequestExtendVote,
) -> Result<proto::ResponseExtendVote, Error>
where
A: PlatformApplication<C> + TransactionalApplication<'a>,
A: PlatformApplication<C> + TransactionalApplication<'a> + BlockExecutionApplication,
C: CoreRPCLike,
{
let _timer = crate::metrics::abci_request_duration("extend_vote");
Expand All @@ -24,9 +24,9 @@ where
height,
round,
} = request;
let guarded_block_execution_context = app.platform().block_execution_context.read().unwrap();
let block_execution_context_guard = app.block_execution_context().read().unwrap();
let block_execution_context =
guarded_block_execution_context
block_execution_context_guard
.as_ref()
.ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution(
"block execution context must be set in block begin handler for extend vote",
Expand All @@ -36,12 +36,11 @@ 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.clone())? {
return Err(Error::from(AbciError::RequestForWrongBlockReceived(format!(
return Err(AbciError::RequestForWrongBlockReceived(format!(
"received extend vote request for height: {} round: {}, block: {}; expected height: {} round: {}, block: {}",
height, round, hex::encode(block_hash),
block_state_info.height(), block_state_info.round(), block_state_info.block_hash().map(hex::encode).unwrap_or("None".to_string())
)))
.into());
)).into());
}

// Extend vote with unsigned withdrawal transactions
Expand Down
33 changes: 24 additions & 9 deletions packages/rs-drive-abci/src/abci/handler/finalize_block.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::abci::app::{PlatformApplication, TransactionalApplication};
use crate::abci::app::{BlockExecutionApplication, PlatformApplication, TransactionalApplication};
use crate::error::execution::ExecutionError;
use crate::error::Error;
use crate::execution::types::block_execution_context::v0::BlockExecutionContextV0Getters;
use crate::rpc::core::CoreRPCLike;
use tenderdash_abci::proto::abci as proto;

Expand All @@ -9,23 +10,39 @@ pub fn finalize_block<'a, A, C>(
request: proto::RequestFinalizeBlock,
) -> Result<proto::ResponseFinalizeBlock, Error>
where
A: PlatformApplication<C> + TransactionalApplication<'a>,
A: PlatformApplication<C> + TransactionalApplication<'a> + BlockExecutionApplication,
C: CoreRPCLike,
{
let _timer = crate::metrics::abci_request_duration("finalize_block");

let transaction_guard = app.transaction().read().unwrap();

let transaction =
transaction_guard
.as_ref()
.ok_or(Error::Execution(ExecutionError::NotInTransaction(
"trying to finalize block without a current transaction",
)))?;

let block_finalization_outcome = app
.platform()
.finalize_block_proposal(request.try_into()?, transaction)?;
// Get current block platform version
let block_execution_context = app
.block_execution_context()
.write()
.unwrap()
.take()
.ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution(
"block execution context must be set in block begin handler for finalize block",
)))?;

let platform_version = app.platform().state.load().current_platform_version()?;

let block_finalization_outcome = app.platform().finalize_block_proposal(
request.try_into()?,
block_execution_context,
transaction,
platform_version,
)?;

drop(transaction_guard);

//FIXME: tell tenderdash about the problem instead
// This can not go to production!
Expand All @@ -40,9 +57,7 @@ where
));
}

drop(transaction_guard);

app.commit_transaction()?;
app.commit_transaction(platform_version)?;

Ok(proto::ResponseFinalizeBlock {
events: vec![],
Expand Down
Loading

0 comments on commit 22137c7

Please sign in to comment.