Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 123f823

Browse files
arkparrphmeier
authored andcommitted
[backport] Transactional updates in the state-db (#1616) (#1626)
* Transactional updates in the state-db (#1616) * set link-arg --export-table for wasm builds (#1598)
1 parent 639cf7a commit 123f823

File tree

14 files changed

+479
-285
lines changed

14 files changed

+479
-285
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/client/db/src/lib.rs

+117-83
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,8 @@ impl<Block: BlockT> Backend<Block> {
608608
};
609609

610610
trace!(target: "db", "Canonicalize block #{} ({:?})", new_canonical, hash);
611-
let commit = self.storage.state_db.canonicalize_block(&hash);
611+
let commit = self.storage.state_db.canonicalize_block(&hash)
612+
.map_err(|e: state_db::Error<io::Error>| client::error::Error::from(format!("State database error: {:?}", e)))?;
612613
apply_state_commit(transaction, commit);
613614
};
614615

@@ -641,7 +642,8 @@ impl<Block: BlockT> Backend<Block> {
641642
let lookup_key = ::utils::number_and_hash_to_lookup_key(f_num, f_hash.clone());
642643
transaction.put(columns::META, meta_keys::FINALIZED_BLOCK, &lookup_key);
643644

644-
let commit = self.storage.state_db.canonicalize_block(&f_hash);
645+
let commit = self.storage.state_db.canonicalize_block(&f_hash)
646+
.map_err(|e: state_db::Error<io::Error>| client::error::Error::from(format!("State database error: {:?}", e)))?;
645647
apply_state_commit(transaction, commit);
646648

647649
// read config from genesis, since it is readonly atm
@@ -654,67 +656,11 @@ impl<Block: BlockT> Backend<Block> {
654656

655657
Ok(())
656658
}
657-
}
658-
659-
fn apply_state_commit(transaction: &mut DBTransaction, commit: state_db::CommitSet<H256>) {
660-
for (key, val) in commit.data.inserted.into_iter() {
661-
transaction.put(columns::STATE, &key[..], &val);
662-
}
663-
for key in commit.data.deleted.into_iter() {
664-
transaction.delete(columns::STATE, &key[..]);
665-
}
666-
for (key, val) in commit.meta.inserted.into_iter() {
667-
transaction.put(columns::STATE_META, &key[..], &val);
668-
}
669-
for key in commit.meta.deleted.into_iter() {
670-
transaction.delete(columns::STATE_META, &key[..]);
671-
}
672-
}
673-
674-
impl<Block> client::backend::AuxStore for Backend<Block> where Block: BlockT<Hash=H256> {
675-
fn insert_aux<
676-
'a,
677-
'b: 'a,
678-
'c: 'a,
679-
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
680-
D: IntoIterator<Item=&'a &'b [u8]>,
681-
>(&self, insert: I, delete: D) -> client::error::Result<()> {
682-
let mut transaction = DBTransaction::new();
683-
for (k, v) in insert {
684-
transaction.put(columns::AUX, k, v);
685-
}
686-
for k in delete {
687-
transaction.delete(columns::AUX, k);
688-
}
689-
self.storage.db.write(transaction).map_err(db_err)?;
690-
Ok(())
691-
}
692-
693-
fn get_aux(&self, key: &[u8]) -> Result<Option<Vec<u8>>, client::error::Error> {
694-
Ok(self.storage.db.get(columns::AUX, key).map(|r| r.map(|v| v.to_vec())).map_err(db_err)?)
695-
}
696-
}
697-
698-
impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> where Block: BlockT<Hash=H256> {
699-
type BlockImportOperation = BlockImportOperation<Block, Blake2Hasher>;
700-
type Blockchain = BlockchainDb<Block>;
701-
type State = CachingState<Blake2Hasher, DbState, Block>;
702-
type ChangesTrieStorage = DbChangesTrieStorage<Block>;
703659

704-
fn begin_operation(&self, block: BlockId<Block>) -> Result<Self::BlockImportOperation, client::error::Error> {
705-
let state = self.state_at(block)?;
706-
Ok(BlockImportOperation {
707-
pending_block: None,
708-
old_state: state,
709-
db_updates: MemoryDB::default(),
710-
storage_updates: Default::default(),
711-
changes_trie_updates: MemoryDB::default(),
712-
aux_ops: Vec::new(),
713-
})
714-
}
715-
716-
fn commit_operation(&self, mut operation: Self::BlockImportOperation)
660+
fn try_commit_operation(&self, mut operation: BlockImportOperation<Block, Blake2Hasher>)
717661
-> Result<(), client::error::Error>
662+
where
663+
Block: BlockT<Hash=H256>,
718664
{
719665
let mut transaction = DBTransaction::new();
720666
operation.apply_aux(&mut transaction);
@@ -747,7 +693,7 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
747693
retracted.push(r.hash.clone());
748694
if r.hash == meta.finalized_hash {
749695
warn!("Potential safety failure: reverting finalized block {:?}",
750-
(&r.number, &r.hash));
696+
(&r.number, &r.hash));
751697

752698
return Err(::client::error::ErrorKind::NotInFinalizedChain.into());
753699
}
@@ -812,22 +758,27 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
812758
let commit = self.storage.state_db.insert_block(&hash, number_u64, &pending_block.header.parent_hash(), changeset)
813759
.map_err(|e: state_db::Error<io::Error>| client::error::Error::from(format!("State database error: {:?}", e)))?;
814760
apply_state_commit(&mut transaction, commit);
815-
self.changes_tries_storage.commit(&mut transaction, operation.changes_trie_updates);
816761

817762
let finalized = match pending_block.leaf_state {
818763
NewBlockState::Final => true,
819764
_ => false,
820765
};
821766

767+
let header = &pending_block.header;
768+
let is_best = pending_block.leaf_state.is_best();
769+
let changes_trie_updates = operation.changes_trie_updates;
770+
771+
772+
self.changes_tries_storage.commit(&mut transaction, changes_trie_updates);
773+
822774
if finalized {
823775
// TODO: ensure best chain contains this block.
824776
self.note_finalized(&mut transaction, &pending_block.header, hash)?;
825777
} else {
826778
// canonicalize blocks which are old enough, regardless of finality.
827-
self.force_delayed_canonicalize(&mut transaction, hash, *pending_block.header.number())?
779+
self.force_delayed_canonicalize(&mut transaction, hash, *header.number())?
828780
}
829781

830-
let is_best = pending_block.leaf_state.is_best();
831782
debug!(target: "db", "DB Commit {:?} ({}), best = {}", hash, number, is_best);
832783

833784
{
@@ -849,7 +800,7 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
849800
self.blockchain.update_meta(
850801
hash.clone(),
851802
number.clone(),
852-
pending_block.leaf_state.is_best(),
803+
is_best,
853804
finalized,
854805
);
855806

@@ -865,31 +816,114 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
865816
}
866817
Ok(())
867818
}
819+
}
820+
821+
fn apply_state_commit(transaction: &mut DBTransaction, commit: state_db::CommitSet<H256>) {
822+
for (key, val) in commit.data.inserted.into_iter() {
823+
transaction.put(columns::STATE, &key[..], &val);
824+
}
825+
for key in commit.data.deleted.into_iter() {
826+
transaction.delete(columns::STATE, &key[..]);
827+
}
828+
for (key, val) in commit.meta.inserted.into_iter() {
829+
transaction.put(columns::STATE_META, &key[..], &val);
830+
}
831+
for key in commit.meta.deleted.into_iter() {
832+
transaction.delete(columns::STATE_META, &key[..]);
833+
}
834+
}
835+
836+
impl<Block> client::backend::AuxStore for Backend<Block> where Block: BlockT<Hash=H256> {
837+
fn insert_aux<
838+
'a,
839+
'b: 'a,
840+
'c: 'a,
841+
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
842+
D: IntoIterator<Item=&'a &'b [u8]>,
843+
>(&self, insert: I, delete: D) -> client::error::Result<()> {
844+
let mut transaction = DBTransaction::new();
845+
for (k, v) in insert {
846+
transaction.put(columns::AUX, k, v);
847+
}
848+
for k in delete {
849+
transaction.delete(columns::AUX, k);
850+
}
851+
self.storage.db.write(transaction).map_err(db_err)?;
852+
Ok(())
853+
}
854+
855+
fn get_aux(&self, key: &[u8]) -> Result<Option<Vec<u8>>, client::error::Error> {
856+
Ok(self.storage.db.get(columns::AUX, key).map(|r| r.map(|v| v.to_vec())).map_err(db_err)?)
857+
}
858+
}
859+
860+
impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> where Block: BlockT<Hash=H256> {
861+
type BlockImportOperation = BlockImportOperation<Block, Blake2Hasher>;
862+
type Blockchain = BlockchainDb<Block>;
863+
type State = CachingState<Blake2Hasher, DbState, Block>;
864+
type ChangesTrieStorage = DbChangesTrieStorage<Block>;
865+
866+
fn begin_operation(&self, block: BlockId<Block>) -> Result<Self::BlockImportOperation, client::error::Error> {
867+
let state = self.state_at(block)?;
868+
Ok(BlockImportOperation {
869+
pending_block: None,
870+
old_state: state,
871+
db_updates: MemoryDB::default(),
872+
storage_updates: Default::default(),
873+
changes_trie_updates: MemoryDB::default(),
874+
aux_ops: Vec::new(),
875+
})
876+
}
877+
878+
fn commit_operation(&self, operation: Self::BlockImportOperation)
879+
-> Result<(), client::error::Error>
880+
{
881+
match self.try_commit_operation(operation) {
882+
Ok(_) => {
883+
self.storage.state_db.apply_pending();
884+
Ok(())
885+
},
886+
e @ Err(_) => {
887+
self.storage.state_db.revert_pending();
888+
e
889+
}
890+
}
891+
}
868892

869893
fn finalize_block(&self, block: BlockId<Block>, justification: Option<Justification>)
870894
-> Result<(), client::error::Error>
871895
{
872896
use runtime_primitives::traits::Header;
873897

874-
if let Some(header) = ::client::blockchain::HeaderBackend::header(&self.blockchain, block)? {
875-
let mut transaction = DBTransaction::new();
876-
// TODO: ensure best chain contains this block.
877-
let hash = header.hash();
878-
self.note_finalized(&mut transaction, &header, hash.clone())?;
879-
if let Some(justification) = justification {
880-
let number = header.number().clone();
881-
transaction.put(
882-
columns::JUSTIFICATION,
883-
&::utils::number_and_hash_to_lookup_key(number, hash.clone()),
884-
&justification.encode(),
885-
);
898+
let commit = || {
899+
if let Some(header) = ::client::blockchain::HeaderBackend::header(&self.blockchain, block)? {
900+
let mut transaction = DBTransaction::new();
901+
// TODO: ensure best chain contains this block.
902+
let hash = header.hash();
903+
self.note_finalized(&mut transaction, &header, hash.clone())?;
904+
if let Some(justification) = justification {
905+
let number = header.number().clone();
906+
transaction.put(
907+
columns::JUSTIFICATION,
908+
&::utils::number_and_hash_to_lookup_key(number, hash.clone()),
909+
&justification.encode(),
910+
);
911+
}
912+
self.storage.db.write(transaction).map_err(db_err)?;
913+
self.blockchain.update_meta(hash, header.number().clone(), false, true);
914+
Ok(())
915+
} else {
916+
Err(client::error::ErrorKind::UnknownBlock(format!("Cannot finalize block {:?}", block)).into())
917+
}
918+
};
919+
match commit() {
920+
Ok(()) => self.storage.state_db.apply_pending(),
921+
e @ Err(_) => {
922+
self.storage.state_db.revert_pending();
923+
return e;
886924
}
887-
self.storage.db.write(transaction).map_err(db_err)?;
888-
self.blockchain.update_meta(hash, header.number().clone(), false, true);
889-
Ok(())
890-
} else {
891-
Err(client::error::ErrorKind::UnknownBlock(format!("Cannot finalize block {:?}", block)).into())
892925
}
926+
Ok(())
893927
}
894928

895929
fn changes_trie_storage(&self) -> Option<&Self::ChangesTrieStorage> {

core/executor/wasm/Cargo.lock

+11-15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/executor/wasm/build.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ if cargo --version | grep -q "nightly"; then
66
else
77
CARGO_CMD="cargo +nightly"
88
fi
9-
$CARGO_CMD build --target=wasm32-unknown-unknown --release
9+
RUSTFLAGS="-C link-arg=--export-table" $CARGO_CMD build --target=wasm32-unknown-unknown --release
1010
for i in test
1111
do
1212
wasm-gc target/wasm32-unknown-unknown/release/runtime_$i.wasm target/wasm32-unknown-unknown/release/runtime_$i.compact.wasm

0 commit comments

Comments
 (0)