From 61c3d748223e6e70cbb91a9eeb81f0dec3c99644 Mon Sep 17 00:00:00 2001 From: simonjiao Date: Wed, 31 Jan 2024 22:45:36 +0800 Subject: [PATCH] add parents_hash to BlockMetadata txn 1. change type of on-chain-resource BlockMetadataV2 2. handle NewBlockEventV2 3. generate new rpc api 4. update blockmetadata types check 5. upgrade TransactionStorage --- chain/open-block/src/lib.rs | 6 +- chain/tests/test_block_chain.rs | 2 +- etc/starcoin_types.yml | 4 + rpc/api/generated_rpc_schema/chain.json | 10 ++ rpc/api/src/types.rs | 7 +- storage/src/block/mod.rs | 89 +-------------- storage/src/lib.rs | 2 + storage/src/transaction/legacy.rs | 22 ++++ storage/src/transaction/mod.rs | 7 +- storage/src/upgrade.rs | 102 +++++++++++++++++- test-helper/data/BlockMetadata/data | 2 +- test-helper/data/BlockMetadata/hash | 2 +- test-helper/data/BlockMetadata/json | 3 +- test-helper/src/starcoin_dao.rs | 4 +- types/src/block/mod.rs | 37 ++++--- .../src/lib.rs | 4 +- vm/types/src/block_metadata/legacy.rs | 96 +++++++++++++++++ .../mod.rs} | 71 ++++++++++-- .../src/on_chain_resource/block_metadata.rs | 8 +- vm/types/src/transaction/mod.rs | 17 +++ vm/vm-runtime/src/starcoin_vm.rs | 7 +- 21 files changed, 370 insertions(+), 132 deletions(-) create mode 100644 storage/src/transaction/legacy.rs create mode 100644 vm/types/src/block_metadata/legacy.rs rename vm/types/src/{block_metadata.rs => block_metadata/mod.rs} (71%) diff --git a/chain/open-block/src/lib.rs b/chain/open-block/src/lib.rs index 10fefab5ef..52a63e8b7c 100644 --- a/chain/open-block/src/lib.rs +++ b/chain/open-block/src/lib.rs @@ -40,7 +40,6 @@ pub struct OpenedBlock { difficulty: U256, strategy: ConsensusStrategy, vm_metrics: Option, - tips_hash: Option>, blue_blocks: Option>, } @@ -71,7 +70,7 @@ impl OpenedBlock { let chain_state = ChainStateDB::new(storage.into_super_arc(), Some(previous_header.state_root())); let chain_id = previous_header.chain_id(); - let block_meta = BlockMetadata::new( + let block_meta = BlockMetadata::new_with_parents( previous_block_id, block_timestamp, author, @@ -80,6 +79,7 @@ impl OpenedBlock { previous_header.number() + 1, chain_id, previous_header.gas_used(), + tips_hash.unwrap_or_default(), ); let mut opened_block = Self { previous_block_info: block_info, @@ -94,7 +94,6 @@ impl OpenedBlock { difficulty, strategy, vm_metrics, - tips_hash, blue_blocks, }; opened_block.initialize()?; @@ -299,7 +298,6 @@ impl OpenedBlock { self.difficulty, self.strategy, self.block_meta, - self.tips_hash, ); Ok(block_template) } diff --git a/chain/tests/test_block_chain.rs b/chain/tests/test_block_chain.rs index 3d799351f2..9eef26d1cf 100644 --- a/chain/tests/test_block_chain.rs +++ b/chain/tests/test_block_chain.rs @@ -31,7 +31,7 @@ fn test_chain_filter_events() { let event_type_tag = TypeTag::Struct(Box::new(StructTag { address: genesis_address(), module: Identifier::from_str("Block").unwrap(), - name: Identifier::from_str("NewBlockEvent").unwrap(), + name: Identifier::from_str("NewBlockEventV2").unwrap(), type_params: vec![], })); diff --git a/etc/starcoin_types.yml b/etc/starcoin_types.yml index ea11e85123..34cfe67cd0 100644 --- a/etc/starcoin_types.yml +++ b/etc/starcoin_types.yml @@ -47,6 +47,10 @@ BlockMetadata: - chain_id: TYPENAME: ChainId - parent_gas_used: U64 + - parents_hash: + OPTION: + SEQ: + TYPENAME: HashValue ChainId: STRUCT: - id: U8 diff --git a/rpc/api/generated_rpc_schema/chain.json b/rpc/api/generated_rpc_schema/chain.json index 46b516cb1a..8bda677a51 100644 --- a/rpc/api/generated_rpc_schema/chain.json +++ b/rpc/api/generated_rpc_schema/chain.json @@ -2179,6 +2179,16 @@ "type": "string", "format": "HashValue" }, + "parents_hash": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string", + "format": "HashValue" + } + }, "timestamp": { "type": "string" }, diff --git a/rpc/api/src/types.rs b/rpc/api/src/types.rs index 523be0cb14..ccba465351 100644 --- a/rpc/api/src/types.rs +++ b/rpc/api/src/types.rs @@ -668,6 +668,7 @@ pub struct BlockMetadataView { pub number: StrView, pub chain_id: u8, pub parent_gas_used: StrView, + pub parents_hash: Option>, } impl From for BlockMetadataView { @@ -681,6 +682,7 @@ impl From for BlockMetadataView { number, chain_id, parent_gas_used, + parents_hash, ) = origin.into_inner(); BlockMetadataView { parent_hash, @@ -691,6 +693,7 @@ impl From for BlockMetadataView { number: number.into(), chain_id: chain_id.id(), parent_gas_used: parent_gas_used.into(), + parents_hash, } } } @@ -707,8 +710,9 @@ impl Into for BlockMetadataView { number, chain_id, parent_gas_used, + parents_hash, } = self; - BlockMetadata::new( + BlockMetadata::new_with_parents( parent_hash, timestamp.0, author, @@ -717,6 +721,7 @@ impl Into for BlockMetadataView { number.0, genesis_config::ChainId::new(chain_id), parent_gas_used.0, + parents_hash.unwrap_or_default(), ) } } diff --git a/storage/src/block/mod.rs b/storage/src/block/mod.rs index 5549f16825..3f7e3c4341 100644 --- a/storage/src/block/mod.rs +++ b/storage/src/block/mod.rs @@ -2,10 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ define_storage, - storage::{ - CodecKVStore, CodecWriteBatch, ColumnFamily, KeyCodec, SchemaStorage, StorageInstance, - ValueCodec, - }, + storage::{CodecKVStore, StorageInstance, ValueCodec}, BLOCK_BODY_PREFIX_NAME, BLOCK_HEADER_PREFIX_NAME, BLOCK_HEADER_PREFIX_NAME_V2, BLOCK_PREFIX_NAME, BLOCK_PREFIX_NAME_V2, BLOCK_TRANSACTIONS_PREFIX_NAME, BLOCK_TRANSACTION_INFOS_PREFIX_NAME, FAILED_BLOCK_PREFIX_NAME, FAILED_BLOCK_PREFIX_NAME_V2, @@ -422,88 +419,4 @@ impl BlockStorage { self.failed_block_storage .put_raw(block_id, old_block.encode_value()?) } - - fn upgrade_store( - old_store: T1, - store: T2, - batch_size: usize, - ) -> Result - where - K: KeyCodec + Copy, - V1: ValueCodec + Into, - V2: ValueCodec, - T1: SchemaStorage + ColumnFamily, - T2: SchemaStorage + ColumnFamily, - { - let mut total_size: usize = 0; - let mut old_iter = old_store.iter()?; - old_iter.seek_to_first(); - - let mut to_delete = Some(CodecWriteBatch::new()); - let mut to_put = Some(CodecWriteBatch::new()); - let mut item_count = 0; - - for item in old_iter { - let (id, old_block) = item?; - let block: V2 = old_block.into(); - to_delete - .as_mut() - .unwrap() - .delete(id) - .expect("should never fail"); - to_put - .as_mut() - .unwrap() - .put(id, block) - .expect("should never fail"); - - item_count += 1; - if item_count == batch_size { - total_size = total_size.saturating_add(item_count); - item_count = 0; - old_store - .write_batch(to_delete.take().unwrap()) - .expect("should never fail"); - store - .write_batch(to_put.take().unwrap()) - .expect("should never fail"); - - to_delete = Some(CodecWriteBatch::new()); - to_put = Some(CodecWriteBatch::new()); - } - } - if item_count != 0 { - total_size = total_size.saturating_add(item_count); - old_store - .write_batch(to_delete.take().unwrap()) - .expect("should never fail"); - store - .write_batch(to_put.take().unwrap()) - .expect("should never fail"); - } - - Ok(total_size) - } - - pub fn upgrade_block_header(instance: StorageInstance) -> Result<()> { - const BATCH_SIZE: usize = 1000usize; - - let old_header_store = OldBlockHeaderStorage::new(instance.clone()); - let header_store = BlockHeaderStorage::new(instance.clone()); - let total_size = Self::upgrade_store(old_header_store, header_store, BATCH_SIZE)?; - info!("upgraded {total_size} block headers"); - - let old_block_store = OldBlockInnerStorage::new(instance.clone()); - let block_store = BlockInnerStorage::new(instance.clone()); - let total_blocks = Self::upgrade_store(old_block_store, block_store, BATCH_SIZE)?; - info!("upgraded {total_blocks} blocks"); - - let old_failed_block_store = OldFailedBlockStorage::new(instance.clone()); - let failed_block_store = FailedBlockStorage::new(instance); - let total_failed_blocks = - Self::upgrade_store(old_failed_block_store, failed_block_store, BATCH_SIZE)?; - info!("upgraded {total_failed_blocks} failed_blocks"); - - Ok(()) - } } diff --git a/storage/src/lib.rs b/storage/src/lib.rs index f2fc3f33f1..fe44c6ff74 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -73,6 +73,7 @@ pub const STATE_NODE_PREFIX_NAME: ColumnFamilyName = "state_node"; pub const STATE_NODE_PREFIX_NAME_PREV: ColumnFamilyName = "state_node_prev"; pub const CHAIN_INFO_PREFIX_NAME: ColumnFamilyName = "chain_info"; pub const TRANSACTION_PREFIX_NAME: ColumnFamilyName = "transaction"; +pub const TRANSACTION_PREFIX_NAME_V2: ColumnFamilyName = "transaction_v2"; pub const TRANSACTION_INFO_PREFIX_NAME: ColumnFamilyName = "transaction_info"; pub const TRANSACTION_INFO_PREFIX_NAME_V2: ColumnFamilyName = "transaction_info_v2"; pub const TRANSACTION_INFO_HASH_PREFIX_NAME: ColumnFamilyName = "transaction_info_hash"; @@ -168,6 +169,7 @@ static VEC_PREFIX_NAME_V4: Lazy> = Lazy::new(|| { CONTRACT_EVENT_PREFIX_NAME, FAILED_BLOCK_PREFIX_NAME, FAILED_BLOCK_PREFIX_NAME_V2, + TRANSACTION_PREFIX_NAME_V2, TABLE_INFO_PREFIX_NAME, ] }); diff --git a/storage/src/transaction/legacy.rs b/storage/src/transaction/legacy.rs new file mode 100644 index 0000000000..cceae2b276 --- /dev/null +++ b/storage/src/transaction/legacy.rs @@ -0,0 +1,22 @@ +use crate::storage::ValueCodec; +use crate::{define_storage, TRANSACTION_PREFIX_NAME}; +use bcs_ext::BCSCodec; +use starcoin_crypto::HashValue; +use starcoin_vm_types::transaction::LegacyTransaction; + +define_storage!( + LegacyTransactionStorage, + HashValue, + LegacyTransaction, + TRANSACTION_PREFIX_NAME +); + +impl ValueCodec for LegacyTransaction { + fn encode_value(&self) -> anyhow::Result> { + self.encode() + } + + fn decode_value(data: &[u8]) -> anyhow::Result { + Self::decode(data) + } +} diff --git a/storage/src/transaction/mod.rs b/storage/src/transaction/mod.rs index ffbb7f2302..dbaf7132c0 100644 --- a/storage/src/transaction/mod.rs +++ b/storage/src/transaction/mod.rs @@ -2,10 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 use crate::storage::{CodecKVStore, CodecWriteBatch, ValueCodec}; -use crate::TRANSACTION_PREFIX_NAME; -use crate::{define_storage, TransactionStore}; +use crate::{define_storage, TransactionStore, TRANSACTION_PREFIX_NAME_V2}; use anyhow::Result; use bcs_ext::BCSCodec; +pub use legacy::LegacyTransactionStorage; use starcoin_crypto::HashValue; use starcoin_types::transaction::Transaction; @@ -13,7 +13,7 @@ define_storage!( TransactionStorage, HashValue, Transaction, - TRANSACTION_PREFIX_NAME + TRANSACTION_PREFIX_NAME_V2 ); impl ValueCodec for Transaction { @@ -46,5 +46,6 @@ impl TransactionStore for TransactionStorage { } } +mod legacy; #[cfg(test)] mod test; diff --git a/storage/src/upgrade.rs b/storage/src/upgrade.rs index c5881649c5..67d06cbb67 100644 --- a/storage/src/upgrade.rs +++ b/storage/src/upgrade.rs @@ -1,10 +1,14 @@ // Copyright (c) The Starcoin Core Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::block::BlockStorage; +use crate::block::{ + BlockHeaderStorage, BlockInnerStorage, BlockStorage, FailedBlockStorage, OldBlockHeaderStorage, + OldBlockInnerStorage, OldFailedBlockStorage, +}; use crate::block_info::BlockInfoStorage; use crate::chain_info::ChainInfoStorage; -use crate::transaction::TransactionStorage; +use crate::storage::{CodecWriteBatch, ColumnFamily, KeyCodec, SchemaStorage, ValueCodec}; +use crate::transaction::{LegacyTransactionStorage, TransactionStorage}; use crate::transaction_info::OldTransactionInfoStorage; use crate::transaction_info::TransactionInfoStorage; use crate::{ @@ -164,7 +168,8 @@ impl DBUpgrade { } fn db_upgrade_v3_v4(instance: &mut StorageInstance) -> Result<()> { - BlockStorage::upgrade_block_header(instance.clone())?; + upgrade_block_header(instance.clone())?; + upgrade_transaction(instance.clone())?; Ok(()) } @@ -252,3 +257,94 @@ impl DBUpgrade { Ok(()) } } + +fn upgrade_store(old_store: T1, store: T2, batch_size: usize) -> Result +where + K: KeyCodec + Copy, + V1: ValueCodec + Into, + V2: ValueCodec, + T1: SchemaStorage + ColumnFamily, + T2: SchemaStorage + ColumnFamily, +{ + let mut total_size: usize = 0; + let mut old_iter = old_store.iter()?; + old_iter.seek_to_first(); + + let mut to_delete = Some(CodecWriteBatch::new()); + let mut to_put = Some(CodecWriteBatch::new()); + let mut item_count = 0; + + for item in old_iter { + let (id, old_block) = item?; + let block: V2 = old_block.into(); + to_delete + .as_mut() + .unwrap() + .delete(id) + .expect("should never fail"); + to_put + .as_mut() + .unwrap() + .put(id, block) + .expect("should never fail"); + + item_count += 1; + if item_count == batch_size { + total_size = total_size.saturating_add(item_count); + item_count = 0; + old_store + .write_batch(to_delete.take().unwrap()) + .expect("should never fail"); + store + .write_batch(to_put.take().unwrap()) + .expect("should never fail"); + + to_delete = Some(CodecWriteBatch::new()); + to_put = Some(CodecWriteBatch::new()); + } + } + if item_count != 0 { + total_size = total_size.saturating_add(item_count); + old_store + .write_batch(to_delete.take().unwrap()) + .expect("should never fail"); + store + .write_batch(to_put.take().unwrap()) + .expect("should never fail"); + } + + Ok(total_size) +} + +fn upgrade_block_header(instance: StorageInstance) -> Result<()> { + const BATCH_SIZE: usize = 1000usize; + + let old_header_store = OldBlockHeaderStorage::new(instance.clone()); + let header_store = BlockHeaderStorage::new(instance.clone()); + let total_size = upgrade_store(old_header_store, header_store, BATCH_SIZE)?; + info!("upgraded {total_size} block headers"); + + let old_block_store = OldBlockInnerStorage::new(instance.clone()); + let block_store = BlockInnerStorage::new(instance.clone()); + let total_blocks = upgrade_store(old_block_store, block_store, BATCH_SIZE)?; + info!("upgraded {total_blocks} blocks"); + + let old_failed_block_store = OldFailedBlockStorage::new(instance.clone()); + let failed_block_store = FailedBlockStorage::new(instance); + let total_failed_blocks = + upgrade_store(old_failed_block_store, failed_block_store, BATCH_SIZE)?; + info!("upgraded {total_failed_blocks} failed_blocks"); + + Ok(()) +} + +fn upgrade_transaction(instance: StorageInstance) -> Result<()> { + const BATCH_SIZE: usize = 1000usize; + + let old_txn_store = LegacyTransactionStorage::new(instance.clone()); + let txn_store = TransactionStorage::new(instance); + let total_size = upgrade_store(old_txn_store, txn_store, BATCH_SIZE)?; + info!("upgraded {total_size} Transactions"); + + Ok(()) +} diff --git a/test-helper/data/BlockMetadata/data b/test-helper/data/BlockMetadata/data index 68cfad2845..02f505bc96 100644 --- a/test-helper/data/BlockMetadata/data +++ b/test-helper/data/BlockMetadata/data @@ -1 +1 @@ -2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000ff0000000000000000 \ No newline at end of file +2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000ff00000000000000000100 \ No newline at end of file diff --git a/test-helper/data/BlockMetadata/hash b/test-helper/data/BlockMetadata/hash index c79ea8ca99..65c3c0b642 100644 --- a/test-helper/data/BlockMetadata/hash +++ b/test-helper/data/BlockMetadata/hash @@ -1 +1 @@ -dd06255ab50b0cf641e5612472d4c71e5339709bf7aaacfeba51bc5b9bafd55d \ No newline at end of file +a6882a425b763ee19b08587d205af69ef27c763a5a22f2d1c3fd698b0658d59b \ No newline at end of file diff --git a/test-helper/data/BlockMetadata/json b/test-helper/data/BlockMetadata/json index a1735e31cb..f2cfb53b48 100644 --- a/test-helper/data/BlockMetadata/json +++ b/test-helper/data/BlockMetadata/json @@ -8,5 +8,6 @@ "chain_id": { "id": 255 }, - "parent_gas_used": 0 + "parent_gas_used": 0, + "parents_hash": [] } \ No newline at end of file diff --git a/test-helper/src/starcoin_dao.rs b/test-helper/src/starcoin_dao.rs index 077eba2667..36f6f93d9f 100644 --- a/test-helper/src/starcoin_dao.rs +++ b/test-helper/src/starcoin_dao.rs @@ -415,7 +415,7 @@ fn stake_to_be_member_function( } fn block_from_metadata(block_meta: BlockMetadata, chain_state: &ChainStateDB) -> Result { - let (parent_hash, timestamp, author, _author_auth_key, _, number, _, _) = + let (parent_hash, timestamp, author, _author_auth_key, _, number, _, _, parents_hash) = block_meta.into_inner(); let block_body = BlockBody::new(vec![], None); let block_header = BlockHeader::new( @@ -432,7 +432,7 @@ fn block_from_metadata(block_meta: BlockMetadata, chain_state: &ChainStateDB) -> chain_state.get_chain_id()?, 0, BlockHeaderExtra::new([0u8; 4]), - None, + parents_hash, ); Ok(Block::new(block_header, block_body)) } diff --git a/types/src/block/mod.rs b/types/src/block/mod.rs index 26c1d2d26f..53abb68012 100644 --- a/types/src/block/mod.rs +++ b/types/src/block/mod.rs @@ -882,16 +882,30 @@ impl Block { .as_ref() .map(|uncles| uncles.len() as u64) .unwrap_or(0); - BlockMetadata::new( - self.header.parent_hash(), - self.header.timestamp, - self.header.author, - self.header.author_auth_key, - uncles, - self.header.number, - self.header.chain_id, - parent_gas_used, - ) + if let Some(parents_hash) = self.header.parents_hash() { + BlockMetadata::new_with_parents( + self.header.parent_hash(), + self.header.timestamp, + self.header.author, + self.header.author_auth_key, + uncles, + self.header.number, + self.header.chain_id, + parent_gas_used, + parents_hash, + ) + } else { + BlockMetadata::new( + self.header.parent_hash(), + self.header.timestamp, + self.header.author, + self.header.author_auth_key, + uncles, + self.header.number, + self.header.chain_id, + parent_gas_used, + ) + } } pub fn random() -> Self { @@ -1043,9 +1057,8 @@ impl BlockTemplate { difficulty: U256, strategy: ConsensusStrategy, block_metadata: BlockMetadata, - parents_hash: ParentsHash, ) -> Self { - let (parent_hash, timestamp, author, _author_auth_key, _, number, _, _) = + let (parent_hash, timestamp, author, _author_auth_key, _, number, _, _, parents_hash) = block_metadata.into_inner(); Self { parent_hash, diff --git a/vm/starcoin-transactional-test-harness/src/lib.rs b/vm/starcoin-transactional-test-harness/src/lib.rs index 633f35d797..b71315bf99 100644 --- a/vm/starcoin-transactional-test-harness/src/lib.rs +++ b/vm/starcoin-transactional-test-harness/src/lib.rs @@ -854,7 +854,7 @@ impl<'a> StarcoinTestAdapter<'a> { e })?; - let (parent_hash, timestamp, author, _author_auth_key, _, number, _, _) = + let (parent_hash, timestamp, author, _author_auth_key, _, number, _, _, parents_hash) = new_block_meta.clone().into_inner(); let block_body = BlockBody::new(vec![], None); let block_header = BlockHeader::new( @@ -871,7 +871,7 @@ impl<'a> StarcoinTestAdapter<'a> { self.context.storage.get_chain_id()?, 0, BlockHeaderExtra::new([0u8; 4]), - None, + parents_hash, ); let new_block = Block::new(block_header, block_body); let mut chain = self.context.chain.lock().unwrap(); diff --git a/vm/types/src/block_metadata/legacy.rs b/vm/types/src/block_metadata/legacy.rs new file mode 100644 index 0000000000..68f9f431e3 --- /dev/null +++ b/vm/types/src/block_metadata/legacy.rs @@ -0,0 +1,96 @@ +use crate::genesis_config::ChainId; +use crate::transaction::authenticator::AuthenticationKey; +use anyhow::anyhow; +use move_core_types::account_address::AccountAddress; +use serde::{Deserialize, Deserializer, Serialize}; +use starcoin_crypto::hash::{CryptoHash, CryptoHasher, PlainCryptoHash}; +use starcoin_crypto::HashValue; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, CryptoHasher, CryptoHash)] +pub struct BlockMetadata { + #[serde(skip)] + pub(super) id: Option, + /// Parent block hash. + pub(super) parent_hash: HashValue, + pub(super) timestamp: u64, + pub(super) author: AccountAddress, + pub(super) author_auth_key: Option, + pub(super) uncles: u64, + pub(super) number: u64, + pub(super) chain_id: ChainId, + pub(super) parent_gas_used: u64, +} + +impl<'de> Deserialize<'de> for BlockMetadata { + fn deserialize(deserializer: D) -> Result>::Error> + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(rename = "BlockMetadata")] + struct BlockMetadataData { + parent_hash: HashValue, + timestamp: u64, + author: AccountAddress, + author_auth_key: Option, + uncles: u64, + number: u64, + chain_id: ChainId, + parent_gas_used: u64, + } + let data = BlockMetadataData::deserialize(deserializer)?; + let mut txn = Self { + id: None, + parent_hash: data.parent_hash, + timestamp: data.timestamp, + author: data.author, + author_auth_key: data.author_auth_key, + uncles: data.uncles, + number: data.number, + chain_id: data.chain_id, + parent_gas_used: data.parent_gas_used, + }; + txn.id = Some(txn.crypto_hash()); + Ok(txn) + } +} + +impl From for super::BlockMetadata { + fn from(value: BlockMetadata) -> Self { + Self { + id: value.id, + parent_hash: value.parent_hash, + timestamp: value.timestamp, + author: value.author, + author_auth_key: value.author_auth_key, + uncles: value.uncles, + number: value.number, + chain_id: value.chain_id, + parent_gas_used: value.parent_gas_used, + parents_hash: None, + } + } +} + +impl TryFrom for BlockMetadata { + type Error = anyhow::Error; + + fn try_from(value: super::BlockMetadata) -> Result { + if value.parents_hash.is_some() { + return Err(anyhow!( + "Can't convert a new BlockMetaData txn with parents_hash to an old one" + )); + } + Ok(Self { + id: value.id, + parent_hash: value.parent_hash, + timestamp: value.timestamp, + author: value.author, + author_auth_key: value.author_auth_key, + uncles: value.uncles, + number: value.number, + chain_id: value.chain_id, + parent_gas_used: value.parent_gas_used, + }) + } +} diff --git a/vm/types/src/block_metadata.rs b/vm/types/src/block_metadata/mod.rs similarity index 71% rename from vm/types/src/block_metadata.rs rename to vm/types/src/block_metadata/mod.rs index 0064ddd9e3..b8a670db9b 100644 --- a/vm/types/src/block_metadata.rs +++ b/vm/types/src/block_metadata/mod.rs @@ -4,11 +4,14 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 +mod legacy; + use crate::account_address::AccountAddress; use crate::account_config::genesis_address; use crate::genesis_config::ChainId; use crate::transaction::authenticator::AuthenticationKey; use bcs_ext::Sample; +pub use legacy::BlockMetadata as LegacyBlockMetadata; use serde::{Deserialize, Deserializer, Serialize}; use starcoin_crypto::hash::PlainCryptoHash; use starcoin_crypto::{ @@ -41,6 +44,7 @@ pub struct BlockMetadata { number: u64, chain_id: ChainId, parent_gas_used: u64, + parents_hash: Option>, } impl BlockMetadata { @@ -53,6 +57,32 @@ impl BlockMetadata { number: u64, chain_id: ChainId, parent_gas_used: u64, + ) -> Self { + let mut txn = legacy::BlockMetadata { + id: None, + parent_hash, + timestamp, + author, + author_auth_key, + uncles, + number, + chain_id, + parent_gas_used, + }; + txn.id = Some(txn.crypto_hash()); + txn.into() + } + + pub fn new_with_parents( + parent_hash: HashValue, + timestamp: u64, + author: AccountAddress, + author_auth_key: Option, + uncles: u64, + number: u64, + chain_id: ChainId, + parent_gas_used: u64, + parents_hash: Vec, ) -> Self { let mut txn = Self { id: None, @@ -64,6 +94,7 @@ impl BlockMetadata { number, chain_id, parent_gas_used, + parents_hash: Some(parents_hash), }; txn.id = Some(txn.crypto_hash()); txn @@ -80,6 +111,7 @@ impl BlockMetadata { u64, ChainId, u64, + Option>, ) { ( self.parent_hash, @@ -90,6 +122,7 @@ impl BlockMetadata { self.number, self.chain_id, self.parent_gas_used, + self.parents_hash, ) } @@ -135,24 +168,39 @@ impl<'de> Deserialize<'de> for BlockMetadata { number: u64, chain_id: ChainId, parent_gas_used: u64, + parents_hash: Option>, } let data = BlockMetadataData::deserialize(deserializer)?; - Ok(Self::new( - data.parent_hash, - data.timestamp, - data.author, - data.author_auth_key, - data.uncles, - data.number, - data.chain_id, - data.parent_gas_used, - )) + Ok(if let Some(parents_hash) = data.parents_hash { + Self::new_with_parents( + data.parent_hash, + data.timestamp, + data.author, + data.author_auth_key, + data.uncles, + data.number, + data.chain_id, + data.parent_gas_used, + parents_hash, + ) + } else { + Self::new( + data.parent_hash, + data.timestamp, + data.author, + data.author_auth_key, + data.uncles, + data.number, + data.chain_id, + data.parent_gas_used, + ) + }) } } impl Sample for BlockMetadata { fn sample() -> Self { - Self::new( + Self::new_with_parents( HashValue::zero(), 0, genesis_address(), @@ -161,6 +209,7 @@ impl Sample for BlockMetadata { 0, ChainId::test(), 0, + vec![], ) } } diff --git a/vm/types/src/on_chain_resource/block_metadata.rs b/vm/types/src/on_chain_resource/block_metadata.rs index c542110770..f35934e143 100644 --- a/vm/types/src/on_chain_resource/block_metadata.rs +++ b/vm/types/src/on_chain_resource/block_metadata.rs @@ -36,11 +36,17 @@ pub struct BlockMetadataV2 { // Author of the current block. pub author: AccountAddress, pub uncles: u64, - pub parents_hash: Vec, + pub parents_hash: Vec, // Handle where events with the time of new blocks are emitted pub new_block_events: EventHandle, } +impl BlockMetadataV2 { + pub fn parents_hash(&self) -> anyhow::Result> { + bcs_ext::from_bytes(self.parents_hash.as_slice()) + } +} + impl MoveResource for BlockMetadataV2 { const MODULE_NAME: &'static str = "Block"; const STRUCT_NAME: &'static str = "BlockMetadataV2"; diff --git a/vm/types/src/transaction/mod.rs b/vm/types/src/transaction/mod.rs index 5a083a80ec..4ab92dbf84 100644 --- a/vm/types/src/transaction/mod.rs +++ b/vm/types/src/transaction/mod.rs @@ -884,6 +884,23 @@ pub enum Transaction { BlockMetadata(BlockMetadata), } +#[allow(clippy::large_enum_variant)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename = "Transaction")] +pub enum LegacyTransaction { + UserTransaction(SignedUserTransaction), + BlockMetadata(#[serde(rename = "BlockMetadata")] super::block_metadata::LegacyBlockMetadata), +} + +impl From for Transaction { + fn from(value: LegacyTransaction) -> Self { + match value { + LegacyTransaction::UserTransaction(txn) => Self::UserTransaction(txn), + LegacyTransaction::BlockMetadata(meta) => Self::BlockMetadata(meta.into()), + } + } +} + impl Transaction { pub fn as_signed_user_txn(&self) -> Result<&SignedUserTransaction> { match self { diff --git a/vm/vm-runtime/src/starcoin_vm.rs b/vm/vm-runtime/src/starcoin_vm.rs index 8850da3403..bbf3b9855e 100644 --- a/vm/vm-runtime/src/starcoin_vm.rs +++ b/vm/vm-runtime/src/starcoin_vm.rs @@ -12,6 +12,7 @@ use crate::errors::{ use crate::move_vm_ext::{MoveResolverExt, MoveVmExt, SessionId, SessionOutput}; use anyhow::{bail, format_err, Error, Result}; use move_core_types::gas_algebra::{InternalGasPerByte, NumBytes}; +use move_core_types::vm_status::StatusCode::VALUE_SERIALIZATION_ERROR; use move_table_extension::NativeTableContext; use move_vm_runtime::move_vm_adapter::{PublishModuleBundleOption, SessionAdapter}; use move_vm_runtime::session::Session; @@ -893,6 +894,7 @@ impl StarcoinVM { number, chain_id, parent_gas_used, + parents_hash, ) = block_metadata.into_inner(); let mut function_name = &account_config::G_BLOCK_PROLOGUE_NAME; let mut args_vec = vec![ @@ -911,7 +913,10 @@ impl StarcoinVM { ]; if let Some(version) = stdlib_version { if version >= StdlibVersion::Version(FLEXI_DAG_UPGRADE_VERSION_MARK) { - args_vec.push(MoveValue::vector_u8(Vec::new())); + args_vec.push(MoveValue::vector_u8( + bcs_ext::to_bytes(&parents_hash.unwrap_or_default()) + .or(Err(VMStatus::Error(VALUE_SERIALIZATION_ERROR)))?, + )); function_name = &account_config::G_BLOCK_PROLOGUE_V2_NAME; } }