From 8882941537fc9d96484943e2a6e6364597d5cc6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bego=C3=B1a=20=C3=81lvarez=20de=20la=20Cruz?= Date: Tue, 29 Oct 2024 11:03:02 +0100 Subject: [PATCH 1/4] chore(ts-sdk): update SDK with latest schemas (#3729) --- sdk/graphql-transport/src/generated/queries.ts | 4 ++-- sdk/graphql-transport/src/methods.ts | 1 + sdk/typescript/src/client/types/generated.ts | 9 +++++++-- .../src/graphql/generated/2024.10/schema.graphql | 4 ++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/sdk/graphql-transport/src/generated/queries.ts b/sdk/graphql-transport/src/generated/queries.ts index ac36d66bdf4..af75693d249 100644 --- a/sdk/graphql-transport/src/generated/queries.ts +++ b/sdk/graphql-transport/src/generated/queries.ts @@ -342,7 +342,7 @@ export type AuthenticatorStateCreateTransaction = { export type AuthenticatorStateExpireTransaction = { __typename?: 'AuthenticatorStateExpireTransaction'; - /** The initial version that the AuthenticatorStateUpdate was shared at. */ + /** The initial version that the AuthenticatorStateUpdateV1 was shared at. */ authenticatorObjInitialSharedVersion: Scalars['UInt53']['output']; /** Expire JWKs that have a lower epoch than this. */ minEpoch?: Maybe; @@ -5018,7 +5018,7 @@ export type Validator = { stakingPool?: Maybe; /** The epoch at which this pool became active. */ stakingPoolActivationEpoch?: Maybe; - /** The ID of this validator's `0x3::staking_pool::StakingPool`. */ + /** The ID of this validator's `0x3::staking_pool::StakingPoolV1`. */ stakingPoolId: Scalars['IotaAddress']['output']; /** The total number of IOTA tokens in this pool. */ stakingPoolIotaBalance?: Maybe; diff --git a/sdk/graphql-transport/src/methods.ts b/sdk/graphql-transport/src/methods.ts index 67d420b43ce..46c91c9656c 100644 --- a/sdk/graphql-transport/src/methods.ts +++ b/sdk/graphql-transport/src/methods.ts @@ -799,6 +799,7 @@ export const RPC_METHODS: { iotaTotalSupply: String(systemState.iotaTotalSupply), iotaTreasuryCapId: String(systemState.iotaTreasuryCapId), maxValidatorCount: String(systemState.systemParameters?.maxValidatorCount), + minValidatorCount: String(systemState.systemParameters?.minValidatorCount), minValidatorJoiningStake: String( systemState.systemParameters?.minValidatorJoiningStake, ), diff --git a/sdk/typescript/src/client/types/generated.ts b/sdk/typescript/src/client/types/generated.ts index a8a48b0e2a6..30bcba8d817 100644 --- a/sdk/typescript/src/client/types/generated.ts +++ b/sdk/typescript/src/client/types/generated.ts @@ -228,7 +228,7 @@ export interface EndOfEpochInfo { epochEndTimestamp: string; lastCheckpointId: string; mintedTokensAmount: string; - /** existing fields from `SystemEpochInfoEvent` (without epoch) */ + /** existing fields from `SystemEpochInfoEventV1` (without epoch) */ protocolVersion: string; referenceGasPrice: string; storageCharge: string; @@ -690,6 +690,11 @@ export interface IotaSystemStateSummary { * epoch to go above this. */ maxValidatorCount: string; + /** + * Minimum number of active validators at any moment. We do not allow the number of validators in any + * epoch to go under this. + */ + minValidatorCount: string; /** Lower-bound on the amount of stake required to become a validator. */ minValidatorJoiningStake: string; /** ID of the object that contains the list of new validators that will join at the end of the epoch. */ @@ -1479,7 +1484,7 @@ export type IotaTransactionBlockKind = } /** A transaction which updates global authenticator state */ | { epoch: string; - kind: 'AuthenticatorStateUpdate'; + kind: 'AuthenticatorStateUpdateV1'; new_active_jwks: IotaActiveJwk[]; round: string; } /** A transaction which updates global randomness state */ diff --git a/sdk/typescript/src/graphql/generated/2024.10/schema.graphql b/sdk/typescript/src/graphql/generated/2024.10/schema.graphql index fba63a69734..be787e02e22 100644 --- a/sdk/typescript/src/graphql/generated/2024.10/schema.graphql +++ b/sdk/typescript/src/graphql/generated/2024.10/schema.graphql @@ -191,7 +191,7 @@ type AuthenticatorStateExpireTransaction { """ minEpoch: Epoch """ - The initial version that the AuthenticatorStateUpdate was shared at. + The initial version that the AuthenticatorStateUpdateV1 was shared at. """ authenticatorObjInitialSharedVersion: UInt53! } @@ -4400,7 +4400,7 @@ type Validator { """ stakingPool: MoveObject @deprecated(reason: "The staking pool is a wrapped object. Access its fields directly on the `Validator` type.") """ - The ID of this validator's `0x3::staking_pool::StakingPool`. + The ID of this validator's `0x3::staking_pool::StakingPoolV1`. """ stakingPoolId: IotaAddress! """ From f5b64c5bf62690262f3976b73dc8529a638848ec Mon Sep 17 00:00:00 2001 From: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:32:20 +0100 Subject: [PATCH 2/4] feat!(iota): remove KeyToolCommand::{LoadKeypair, Unpack} (#3223) * feat!(iota): remove KeyToolCommand::LoadKeypair * Remove unused struct KeypairData * feat!(iota): remove KeyToolCommand::Unpack --------- Co-authored-by: Thibault Martinez --- crates/iota/src/keytool.rs | 73 +------------------------ docs/content/references/cli/keytool.mdx | 5 -- 2 files changed, 2 insertions(+), 76 deletions(-) diff --git a/crates/iota/src/keytool.rs b/crates/iota/src/keytool.rs index 059eccb635d..2c9eaf01877 100644 --- a/crates/iota/src/keytool.rs +++ b/crates/iota/src/keytool.rs @@ -4,8 +4,7 @@ use std::{ fmt::{Debug, Display, Formatter}, - fs, - path::{Path, PathBuf}, + path::PathBuf, sync::Arc, }; @@ -150,12 +149,6 @@ pub enum KeyToolCommand { #[clap(long, short = 's')] sort_by_alias: bool, }, - /// This reads the content at the provided file path. The accepted format - /// is a Bech32 encoded [enum IotaKeyPair] or `type AuthorityKeyPair` - /// (Base64 encoded `privkey`). This prints out the account keypair as - /// Base64 encoded `flag || privkey`, the network keypair, protocol - /// keypair, authority keypair as Base64 encoded `privkey`. - LoadKeypair { file: PathBuf }, /// To MultiSig Iota Address. Pass in a list of all public keys `flag || pk` /// in Base64. See `keytool list` for example public keys. MultiSigAddress { @@ -220,11 +213,6 @@ pub enum KeyToolCommand { #[clap(long)] base64pk: String, }, - /// This takes a bech32 encoded [enum IotaKeyPair]. It outputs the keypair - /// into a file at the current directory where the address is the - /// filename, and prints out its Iota address, Base64 encoded public - /// key, the key scheme, and the key scheme flag. - Unpack { keypair: String }, // Commented for now: https://github.com/iotaledger/iota/issues/1777 // /// Given the max_epoch, generate an OAuth url, ask user to paste the // /// redirect with id_token, call salt server, then call the prover server, @@ -356,15 +344,6 @@ pub struct ExportedKey { key: Key, } -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -pub struct KeypairData { - account_keypair: String, - network_keypair: Option, - protocol_keypair: Option, - key_scheme: String, -} - #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct MultiSigAddress { @@ -456,7 +435,6 @@ pub enum CommandOutput { Import(Key), Export(ExportedKey), List(Vec), - LoadKeypair(KeypairData), MultiSigAddress(MultiSigAddress), MultiSigCombinePartialSig(MultiSigCombinePartialSig), Show(Key), @@ -665,44 +643,6 @@ impl KeyToolCommand { } CommandOutput::List(keys) } - KeyToolCommand::LoadKeypair { file } => { - let output = match read_keypair_from_file(&file) { - Ok(keypair) => { - // Account keypair is encoded with the key scheme flag {}, - // and network and protocol keypair are not. - let network_protocol_keypair = match &keypair { - IotaKeyPair::Ed25519(kp) => kp.encode_base64(), - IotaKeyPair::Secp256k1(kp) => kp.encode_base64(), - IotaKeyPair::Secp256r1(kp) => kp.encode_base64(), - }; - KeypairData { - account_keypair: keypair.encode_base64(), - network_keypair: Some(network_protocol_keypair.clone()), - protocol_keypair: Some(network_protocol_keypair), - key_scheme: keypair.public().scheme().to_string(), - } - } - Err(_) => { - // Authority keypair file is not stored with the flag, it will try read as - // BLS keypair.. - match read_authority_keypair_from_file(&file) { - Ok(keypair) => KeypairData { - account_keypair: keypair.encode_base64(), - network_keypair: None, - protocol_keypair: None, - key_scheme: SignatureScheme::BLS12381.to_string(), - }, - Err(e) => { - return Err(anyhow!(format!( - "Failed to read keypair at path {:?} err: {:?}", - file, e - ))); - } - } - } - }; - CommandOutput::LoadKeypair(output) - } KeyToolCommand::MultiSigAddress { threshold, pks, @@ -854,16 +794,7 @@ impl KeyToolCommand { serialized_sig_base64: serialized_sig, }) } - KeyToolCommand::Unpack { keypair } => { - let key = Key::from( - &IotaKeyPair::decode(&keypair) - .map_err(|_| anyhow!("Invalid Bech32 encoded keypair"))?, - ); - let path_str = format!("{}.key", key.iota_address).to_lowercase(); - let path = Path::new(&path_str); - fs::write(path, keypair)?; - CommandOutput::Show(key) - } /* Commented for now: https://github.com/iotaledger/iota/issues/1777 + /* Commented for now: https://github.com/iotaledger/iota/issues/1777 * KeyToolCommand::ZkLoginInsecureSignPersonalMessage { data, max_epoch } => { * let msg = PersonalMessage { * message: data.as_bytes().to_vec(), diff --git a/docs/content/references/cli/keytool.mdx b/docs/content/references/cli/keytool.mdx index f9ab9bcddc2..77a4581fe3b 100644 --- a/docs/content/references/cli/keytool.mdx +++ b/docs/content/references/cli/keytool.mdx @@ -29,9 +29,6 @@ Commands: provided, the tool will automatically generate one export Output the private key of the given key identity in Iota CLI Keystore as Bech32 encoded string starting with `iotaprivkey` list List all keys by its Iota address, Base64 encoded public key, key scheme name in iota.keystore - load-keypair This reads the content at the provided file path. The accepted format can be [enum IotaKeyPair] (Base64 encoded of 33-byte `flag || privkey`) or `type - AuthorityKeyPair` (Base64 encoded `privkey`). This prints out the account keypair as Base64 encoded `flag || privkey`, the network keypair, protocol keypair, - authority keypair as Base64 encoded `privkey` multi-sig-address To MultiSig Iota Address. Pass in a list of all public keys `flag || pk` in Base64. See `keytool list` for example public keys multi-sig-combine-partial-sig Provides a list of participating signatures (`flag || sig || pk` encoded in Base64), threshold, a list of all public keys and a list of their weights that define the MultiSig address. Returns a valid MultiSig signature and its sender address. The result can be used as signature field for `iota client @@ -43,8 +40,6 @@ Commands: sign-kms Creates a signature by leveraging AWS KMS. Pass in a key-id to leverage Amazon KMS to sign a message and the base64 pubkey. Generate PubKey from pem using iotaledger/base64pemkey Any signature commits to a [struct IntentMessage] consisting of the Base64 encoded of the BCS serialized transaction bytes itself and its intent. If intent is absent, default will be used - unpack This takes [enum IotaKeyPair] of Base64 encoded of 33-byte `flag || privkey`). It outputs the keypair into a file at the current directory where the address is - the filename, and prints out its Iota address, Base64 encoded public key, the key scheme, and the key scheme flag help Print this message or the help of the given subcommand(s) Options: From 605d02886e71ce3b84b40a358ce015790429e100 Mon Sep 17 00:00:00 2001 From: Bing-Yang <51323441+bingyanglin@users.noreply.github.com> Date: Tue, 29 Oct 2024 19:06:52 +0800 Subject: [PATCH 3/4] fix(iota-benchmark): fix `test_upgrade_compatibility` (#3732) * Fix test_upgrade_compatibility * Update crates/iota-benchmark/tests/simtest.rs Co-authored-by: muXxer * Modify the ProtocolVersion::MAX_ALLOWED * Revert the MAX_ALLOWED to avoid breaking other testings * Use MAX + 1 for protocol upgrade testing for now --------- Co-authored-by: muXxer --- crates/iota-benchmark/tests/simtest.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/iota-benchmark/tests/simtest.rs b/crates/iota-benchmark/tests/simtest.rs index f903d1db610..d59d8a0b66f 100644 --- a/crates/iota-benchmark/tests/simtest.rs +++ b/crates/iota-benchmark/tests/simtest.rs @@ -668,7 +668,8 @@ mod test { } async fn test_protocol_upgrade_compatibility_impl() { - let max_ver = ProtocolVersion::MAX.as_u64(); + // TODO: Remove the `+ 1` after we have Protocol version 2 + let max_ver = ProtocolVersion::MAX.as_u64() + 1; let manifest = iota_framework_snapshot::load_bytecode_snapshot_manifest(); let Some((&starting_version, _)) = manifest.range(..max_ver).last() else { From 83f048346e8fd498485e3ecdd2a36e2b5a8be2ac Mon Sep 17 00:00:00 2001 From: Bing-Yang <51323441+bingyanglin@users.noreply.github.com> Date: Tue, 29 Oct 2024 19:07:21 +0800 Subject: [PATCH 4/4] feat(node): Remove multiple versions of types (Part 2) (#3672) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove ExecutionResultsV1 * Rename ExecutionResults::V2 to be V1 * Rename V2 to V1 * Rebase * Fix clippy * refactor(iota-types): remove TransactionEffectsV2 * refactor(iota-types): update specs * Rename UID versions (#3658) * refactor(core-node): rename `ExecuteTransactionRequest`/`ResponseV3` to version 1 (#3598) * Rebase the new develop * Rename ExecuteTransactionRequestV1::new_v2 to be new_v1 * Rename execute_transaction_v3 to be execute_transaction_v1 * Remove VerifiedExecuteTransactionResponseV1/ExecuteTransactionResponse * Remove ExecuteTransactionRequest * new_v1 to new * refactor(core-node): rename `IotaGasStatusV2` to be `IotaGasStatusV1` (#3660) * Rename gas status versions * Rename gas_v2 to be gas_v1 * Update crates/iota-types/src/gas.rs Co-authored-by: Mirko Zichichi --------- Co-authored-by: Mirko Zichichi * refactor(iota-core): Remove old versions for CheckpointResponse and CheckpointRequest. * refactor(iota-core): Rename CheckpointResponseV2 and CheckpointRequestV2 to CheckpointResponse and CheckpointRequest * refactor(iota-core): Rename handle_checkpoint_request_v2 to handle_checkpoint_request * Update iota-rust-sdk --------- Co-authored-by: miker83z Co-authored-by: Mirko Zichichi Co-authored-by: Daria Dziubałtowska Co-authored-by: Daria Dziubałtowska <44535712+daria305@users.noreply.github.com> Co-authored-by: muXxer Co-authored-by: Thoralf Müller --- Cargo.lock | 2 +- Cargo.toml | 2 +- crates/iota-core/src/authority.rs | 33 +- crates/iota-core/src/authority_client.rs | 22 +- crates/iota-core/src/authority_server.rs | 21 +- crates/iota-core/src/checkpoints/mod.rs | 16 +- crates/iota-core/src/safe_client.rs | 76 -- .../iota-core/src/test_authority_clients.rs | 27 +- .../iota-core/src/validator_tx_finalizer.rs | 11 +- crates/iota-core/tests/staged/iota.yaml | 79 -- crates/iota-network/build.rs | 9 - .../src/displays/gas_status_displays.rs | 8 +- crates/iota-tool/src/commands.rs | 1 + crates/iota-types/src/effects/effects_v1.rs | 721 +++++++++++------- crates/iota-types/src/effects/effects_v2.rs | 613 --------------- crates/iota-types/src/effects/mod.rs | 73 +- .../src/effects/test_effects_builder.rs | 2 +- crates/iota-types/src/execution.rs | 15 +- .../iota-types/src/full_checkpoint_content.rs | 65 +- crates/iota-types/src/gas.rs | 12 +- .../src/gas_model/{gas_v2.rs => gas_v1.rs} | 0 crates/iota-types/src/gas_model/mod.rs | 2 +- crates/iota-types/src/messages_checkpoint.rs | 18 - crates/iota-types/src/quorum_driver_types.rs | 27 - .../iota-adapter/src/execution_engine.rs | 6 +- .../src/programmable_transactions/context.rs | 4 +- .../iota-adapter/src/temporary_store.rs | 18 +- .../src/object_runtime/mod.rs | 12 +- .../v0/iota-adapter/src/execution_engine.rs | 6 +- .../src/programmable_transactions/context.rs | 4 +- .../v0/iota-adapter/src/temporary_store.rs | 18 +- .../src/object_runtime/mod.rs | 12 +- 32 files changed, 553 insertions(+), 1382 deletions(-) delete mode 100644 crates/iota-types/src/effects/effects_v2.rs rename crates/iota-types/src/gas_model/{gas_v2.rs => gas_v1.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index c2fd51fc912..a580c1205b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7626,7 +7626,7 @@ dependencies = [ [[package]] name = "iota-rust-sdk" version = "0.0.0" -source = "git+ssh://git@github.com/iotaledger/iota-rust-sdk.git?rev=46d46d64237e001e8e23f322caecb3211c9a8c97#46d46d64237e001e8e23f322caecb3211c9a8c97" +source = "git+ssh://git@github.com/iotaledger/iota-rust-sdk.git?rev=ed6173d434c77604ddc93aaa1550168fdbe97b09#ed6173d434c77604ddc93aaa1550168fdbe97b09" dependencies = [ "base64ct", "bcs", diff --git a/Cargo.toml b/Cargo.toml index 141904a44f1..08e8fa83e47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -419,7 +419,7 @@ iota-rosetta = { path = "crates/iota-rosetta" } iota-rpc-loadgen = { path = "crates/iota-rpc-loadgen" } iota-sdk = { path = "crates/iota-sdk" } # core-types with json format for REST api -iota-sdk2 = { package = "iota-rust-sdk", git = "ssh://git@github.com/iotaledger/iota-rust-sdk.git", rev = "46d46d64237e001e8e23f322caecb3211c9a8c97", features = ["hash", "serde", "schemars"] } +iota-sdk2 = { package = "iota-rust-sdk", git = "ssh://git@github.com/iotaledger/iota-rust-sdk.git", rev = "ed6173d434c77604ddc93aaa1550168fdbe97b09", features = ["hash", "serde", "schemars"] } iota-simulator = { path = "crates/iota-simulator" } iota-snapshot = { path = "crates/iota-snapshot" } iota-source-validation = { path = "crates/iota-source-validation" } diff --git a/crates/iota-core/src/authority.rs b/crates/iota-core/src/authority.rs index 7eee6f5e8eb..b783c447b90 100644 --- a/crates/iota-core/src/authority.rs +++ b/crates/iota-core/src/authority.rs @@ -84,10 +84,9 @@ use iota_types::{ message_envelope::Message, messages_checkpoint::{ CertifiedCheckpointSummary, CheckpointCommitment, CheckpointContents, - CheckpointContentsDigest, CheckpointDigest, CheckpointRequest, CheckpointRequestV2, - CheckpointResponse, CheckpointResponseV2, CheckpointSequenceNumber, CheckpointSummary, - CheckpointSummaryResponse, CheckpointTimestamp, ECMHLiveObjectSetDigest, - VerifiedCheckpoint, + CheckpointContentsDigest, CheckpointDigest, CheckpointRequest, CheckpointResponse, + CheckpointSequenceNumber, CheckpointSummary, CheckpointSummaryResponse, + CheckpointTimestamp, ECMHLiveObjectSetDigest, VerifiedCheckpoint, }, messages_consensus::AuthorityCapabilitiesV1, messages_grpc::{ @@ -2558,30 +2557,6 @@ impl AuthorityState { &self, request: &CheckpointRequest, ) -> IotaResult { - let summary = match request.sequence_number { - Some(seq) => self - .checkpoint_store - .get_checkpoint_by_sequence_number(seq)?, - None => self.checkpoint_store.get_latest_certified_checkpoint(), - } - .map(|v| v.into_inner()); - let contents = match &summary { - Some(s) => self - .checkpoint_store - .get_checkpoint_contents(&s.content_digest)?, - None => None, - }; - Ok(CheckpointResponse { - checkpoint: summary, - contents, - }) - } - - #[instrument(level = "trace", skip_all)] - pub fn handle_checkpoint_request_v2( - &self, - request: &CheckpointRequestV2, - ) -> IotaResult { let summary = if request.certified { let summary = match request.sequence_number { Some(seq) => self @@ -2606,7 +2581,7 @@ impl AuthorityState { .get_checkpoint_contents(&s.content_digest())?, None => None, }; - Ok(CheckpointResponseV2 { + Ok(CheckpointResponse { checkpoint: summary, contents, }) diff --git a/crates/iota-core/src/authority_client.rs b/crates/iota-core/src/authority_client.rs index 23457b75321..82ace64486f 100644 --- a/crates/iota-core/src/authority_client.rs +++ b/crates/iota-core/src/authority_client.rs @@ -18,9 +18,7 @@ use iota_types::{ committee::CommitteeWithNetworkMetadata, error::{IotaError, IotaResult}, iota_system_state::IotaSystemState, - messages_checkpoint::{ - CheckpointRequest, CheckpointRequestV2, CheckpointResponse, CheckpointResponseV2, - }, + messages_checkpoint::{CheckpointRequest, CheckpointResponse}, messages_grpc::{ HandleCertificateRequestV3, HandleCertificateResponseV2, HandleCertificateResponseV3, HandleSoftBundleCertificatesRequestV3, HandleSoftBundleCertificatesResponseV3, @@ -81,12 +79,6 @@ pub trait AuthorityAPI { request: CheckpointRequest, ) -> Result; - /// Handles a `CheckpointRequestV2` for this account. - async fn handle_checkpoint_v2( - &self, - request: CheckpointRequestV2, - ) -> Result; - // This API is exclusively used by the benchmark code. // Hence it's OK to return a fixed system state type. async fn handle_system_state_object( @@ -243,18 +235,6 @@ impl AuthorityAPI for NetworkAuthorityClient { .map_err(Into::into) } - /// Handles a `CheckpointRequestV2` for this account. - async fn handle_checkpoint_v2( - &self, - request: CheckpointRequestV2, - ) -> Result { - self.client()? - .checkpoint_v2(request) - .await - .map(tonic::Response::into_inner) - .map_err(Into::into) - } - /// This API is exclusively used by the benchmark code. async fn handle_system_state_object( &self, diff --git a/crates/iota-core/src/authority_server.rs b/crates/iota-core/src/authority_server.rs index b842127274f..6c6f12c8ae0 100644 --- a/crates/iota-core/src/authority_server.rs +++ b/crates/iota-core/src/authority_server.rs @@ -23,9 +23,7 @@ use iota_types::{ error::*, fp_ensure, iota_system_state::IotaSystemState, - messages_checkpoint::{ - CheckpointRequest, CheckpointRequestV2, CheckpointResponse, CheckpointResponseV2, - }, + messages_checkpoint::{CheckpointRequest, CheckpointResponse}, messages_consensus::ConsensusTransaction, messages_grpc::{ HandleCertificateRequestV3, HandleCertificateResponseV2, HandleCertificateResponseV3, @@ -927,15 +925,6 @@ impl ValidatorService { Ok((tonic::Response::new(response), Weight::one())) } - async fn checkpoint_v2_impl( - &self, - request: tonic::Request, - ) -> WrappedServiceResponse { - let request = request.into_inner(); - let response = self.state.handle_checkpoint_request_v2(&request)?; - Ok((tonic::Response::new(response), Weight::one())) - } - async fn get_system_state_object_impl( &self, _request: tonic::Request, @@ -1213,14 +1202,6 @@ impl Validator for ValidatorService { handle_with_decoration!(self, checkpoint_impl, request) } - /// Handles a `CheckpointRequestV2` request. - async fn checkpoint_v2( - &self, - request: tonic::Request, - ) -> Result, tonic::Status> { - handle_with_decoration!(self, checkpoint_v2_impl, request) - } - /// Gets the `IotaSystemState` response. async fn get_system_state_object( &self, diff --git a/crates/iota-core/src/checkpoints/mod.rs b/crates/iota-core/src/checkpoints/mod.rs index c7b56a7cd34..f23767c8f84 100644 --- a/crates/iota-core/src/checkpoints/mod.rs +++ b/crates/iota-core/src/checkpoints/mod.rs @@ -42,8 +42,8 @@ use iota_types::{ }, message_envelope::Message, messages_checkpoint::{ - CertifiedCheckpointSummary, CheckpointCommitment, CheckpointContents, CheckpointRequestV2, - CheckpointResponseV2, CheckpointSequenceNumber, CheckpointSignatureMessage, + CertifiedCheckpointSummary, CheckpointCommitment, CheckpointContents, CheckpointRequest, + CheckpointResponse, CheckpointSequenceNumber, CheckpointSignatureMessage, CheckpointSummary, CheckpointSummaryResponse, CheckpointTimestamp, EndOfEpochData, FullCheckpointContents, SignedCheckpointSummary, TrustedCheckpoint, VerifiedCheckpoint, VerifiedCheckpointContents, @@ -2078,12 +2078,12 @@ async fn diagnose_split_brain( let client = network_clients .get(&validator) .expect("Failed to get network client"); - let request = CheckpointRequestV2 { + let request = CheckpointRequest { sequence_number: Some(local_summary.sequence_number), request_content: true, certified: false, }; - client.handle_checkpoint_v2(request) + client.handle_checkpoint(request) }) .collect::>(); @@ -2094,17 +2094,17 @@ async fn diagnose_split_brain( .zip(digest_name_pair) .filter_map(|(response, (digest, name))| match response { Ok(response) => match response { - CheckpointResponseV2 { + CheckpointResponse { checkpoint: Some(CheckpointSummaryResponse::Pending(summary)), contents: Some(contents), } => Some((*name, *digest, summary, contents)), - CheckpointResponseV2 { + CheckpointResponse { checkpoint: Some(CheckpointSummaryResponse::Certified(_)), contents: _, } => { panic!("Expected pending checkpoint, but got certified checkpoint"); } - CheckpointResponseV2 { + CheckpointResponse { checkpoint: None, contents: _, } => { @@ -2114,7 +2114,7 @@ async fn diagnose_split_brain( ); None } - CheckpointResponseV2 { + CheckpointResponse { checkpoint: _, contents: None, } => { diff --git a/crates/iota-core/src/safe_client.rs b/crates/iota-core/src/safe_client.rs index 29468152c1a..57b38aafedd 100644 --- a/crates/iota-core/src/safe_client.rs +++ b/crates/iota-core/src/safe_client.rs @@ -14,9 +14,6 @@ use iota_types::{ error::{IotaError, IotaResult}, fp_ensure, iota_system_state::IotaSystemState, - messages_checkpoint::{ - CertifiedCheckpointSummary, CheckpointRequest, CheckpointResponse, CheckpointSequenceNumber, - }, messages_grpc::{ HandleCertificateRequestV3, HandleCertificateResponseV2, HandleCertificateResponseV3, ObjectInfoRequest, ObjectInfoResponse, SystemStateRequest, TransactionInfoRequest, @@ -529,79 +526,6 @@ where Ok(transaction_info) } - fn verify_checkpoint_sequence( - &self, - expected_seq: Option, - checkpoint: &Option, - ) -> IotaResult { - let observed_seq = checkpoint.as_ref().map(|c| c.sequence_number); - - if let (Some(e), Some(o)) = (expected_seq, observed_seq) { - fp_ensure!( - e == o, - IotaError::from("Expected checkpoint number doesn't match with returned") - ); - } - Ok(()) - } - - fn verify_contents_exist( - &self, - request_content: bool, - checkpoint: &Option, - contents: &Option, - ) -> IotaResult { - match (request_content, checkpoint, contents) { - // If content is requested, checkpoint is not None, but we are not getting any content, - // it's an error. - // If content is not requested, or checkpoint is None, yet we are still getting content, - // it's an error. - (true, Some(_), None) | (false, _, Some(_)) | (_, None, Some(_)) => Err( - IotaError::from("Checkpoint contents inconsistent with request"), - ), - _ => Ok(()), - } - } - - fn verify_checkpoint_response( - &self, - request: &CheckpointRequest, - response: &CheckpointResponse, - ) -> IotaResult { - // Verify response data was correct for request - let CheckpointResponse { - checkpoint, - contents, - } = &response; - // Checks that the sequence number is correct. - self.verify_checkpoint_sequence(request.sequence_number, checkpoint)?; - self.verify_contents_exist(request.request_content, checkpoint, contents)?; - // Verify signature. - match checkpoint { - Some(c) => { - let epoch_id = c.epoch; - c.verify_with_contents(&*self.get_committee(&epoch_id)?, contents.as_ref()) - } - None => Ok(()), - } - } - - #[instrument(level = "trace", skip_all, fields(authority = ?self.address.concise()))] - pub async fn handle_checkpoint( - &self, - request: CheckpointRequest, - ) -> Result { - let resp = self - .authority_client - .handle_checkpoint(request.clone()) - .await?; - self.verify_checkpoint_response(&request, &resp) - .tap_err(|err| { - error!(?err, authority=?self.address, "Client error in handle_checkpoint"); - })?; - Ok(resp) - } - #[instrument(level = "trace", skip_all, fields(authority = ?self.address.concise()))] pub async fn handle_system_state_object(&self) -> Result { self.authority_client diff --git a/crates/iota-core/src/test_authority_clients.rs b/crates/iota-core/src/test_authority_clients.rs index f4272029d0c..fc2d12898d3 100644 --- a/crates/iota-core/src/test_authority_clients.rs +++ b/crates/iota-core/src/test_authority_clients.rs @@ -17,9 +17,7 @@ use iota_types::{ effects::TransactionEffectsAPI, error::{IotaError, IotaResult}, iota_system_state::IotaSystemState, - messages_checkpoint::{ - CheckpointRequest, CheckpointRequestV2, CheckpointResponse, CheckpointResponseV2, - }, + messages_checkpoint::{CheckpointRequest, CheckpointResponse}, messages_grpc::{ HandleCertificateRequestV3, HandleCertificateResponseV2, HandleCertificateResponseV3, HandleSoftBundleCertificatesRequestV3, HandleSoftBundleCertificatesResponseV3, @@ -155,15 +153,6 @@ impl AuthorityAPI for LocalAuthorityClient { state.handle_checkpoint_request(&request) } - async fn handle_checkpoint_v2( - &self, - request: CheckpointRequestV2, - ) -> Result { - let state = self.state.clone(); - - state.handle_checkpoint_request_v2(&request) - } - async fn handle_system_state_object( &self, _request: SystemStateRequest, @@ -355,13 +344,6 @@ impl AuthorityAPI for MockAuthorityApi { unimplemented!(); } - async fn handle_checkpoint_v2( - &self, - _request: CheckpointRequestV2, - ) -> Result { - unimplemented!(); - } - async fn handle_system_state_object( &self, _request: SystemStateRequest, @@ -440,13 +422,6 @@ impl AuthorityAPI for HandleTransactionTestAuthorityClient { unimplemented!() } - async fn handle_checkpoint_v2( - &self, - _request: CheckpointRequestV2, - ) -> Result { - unimplemented!() - } - async fn handle_system_state_object( &self, _request: SystemStateRequest, diff --git a/crates/iota-core/src/validator_tx_finalizer.rs b/crates/iota-core/src/validator_tx_finalizer.rs index 607ad914920..12a2ad27a80 100644 --- a/crates/iota-core/src/validator_tx_finalizer.rs +++ b/crates/iota-core/src/validator_tx_finalizer.rs @@ -289,9 +289,7 @@ mod tests { error::IotaError, executable_transaction::VerifiedExecutableTransaction, iota_system_state::IotaSystemState, - messages_checkpoint::{ - CheckpointRequest, CheckpointRequestV2, CheckpointResponse, CheckpointResponseV2, - }, + messages_checkpoint::{CheckpointRequest, CheckpointResponse}, messages_grpc::{ HandleCertificateRequestV3, HandleCertificateResponseV2, HandleCertificateResponseV3, HandleSoftBundleCertificatesRequestV3, HandleSoftBundleCertificatesResponseV3, @@ -406,13 +404,6 @@ mod tests { unimplemented!() } - async fn handle_checkpoint_v2( - &self, - _request: CheckpointRequestV2, - ) -> Result { - unimplemented!() - } - async fn handle_system_state_object( &self, _request: SystemStateRequest, diff --git a/crates/iota-core/tests/staged/iota.yaml b/crates/iota-core/tests/staged/iota.yaml index 93612022d94..7a2a28721f5 100644 --- a/crates/iota-core/tests/staged/iota.yaml +++ b/crates/iota-core/tests/staged/iota.yaml @@ -868,89 +868,10 @@ TransactionEffects: V1: NEWTYPE: TYPENAME: TransactionEffectsV1 - 1: - V2: - NEWTYPE: - TYPENAME: TransactionEffectsV2 TransactionEffectsDigest: NEWTYPESTRUCT: TYPENAME: Digest TransactionEffectsV1: - STRUCT: - - status: - TYPENAME: ExecutionStatus - - executed_epoch: U64 - - gas_used: - TYPENAME: GasCostSummary - - modified_at_versions: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - shared_objects: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - transaction_digest: - TYPENAME: TransactionDigest - - created: - SEQ: - TUPLE: - - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - TYPENAME: Owner - - mutated: - SEQ: - TUPLE: - - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - TYPENAME: Owner - - unwrapped: - SEQ: - TUPLE: - - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - TYPENAME: Owner - - deleted: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - unwrapped_then_deleted: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - wrapped: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - gas_object: - TUPLE: - - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - TYPENAME: Owner - - events_digest: - OPTION: - TYPENAME: TransactionEventsDigest - - dependencies: - SEQ: - TYPENAME: TransactionDigest -TransactionEffectsV2: STRUCT: - status: TYPENAME: ExecutionStatus diff --git a/crates/iota-network/build.rs b/crates/iota-network/build.rs index 088e92e429f..5f0b6b057ac 100644 --- a/crates/iota-network/build.rs +++ b/crates/iota-network/build.rs @@ -96,15 +96,6 @@ fn main() -> Result<()> { .codec_path(codec_path) .build(), ) - .method( - Method::builder() - .name("checkpoint_v2") - .route_name("CheckpointV2") - .input_type("iota_types::messages_checkpoint::CheckpointRequestV2") - .output_type("iota_types::messages_checkpoint::CheckpointResponseV2") - .codec_path(codec_path) - .build(), - ) .method( Method::builder() .name("get_system_state_object") diff --git a/crates/iota-replay/src/displays/gas_status_displays.rs b/crates/iota-replay/src/displays/gas_status_displays.rs index ad8b8ce9d74..0237a95449c 100644 --- a/crates/iota-replay/src/displays/gas_status_displays.rs +++ b/crates/iota-replay/src/displays/gas_status_displays.rs @@ -4,7 +4,7 @@ use std::fmt::{Display, Formatter}; -use iota_types::{gas::IotaGasStatus, gas_model::gas_v2::IotaGasStatus as GasStatusV2}; +use iota_types::{gas::IotaGasStatus, gas_model::gas_v1::IotaGasStatus as GasStatusV1}; use tabled::{ builder::Builder as TableBuilder, settings::{Style as TableStyle, style::HorizontalLine}, @@ -16,7 +16,7 @@ impl<'a> Display for Pretty<'a, IotaGasStatus> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let Pretty(iota_gas_status) = self; match iota_gas_status { - IotaGasStatus::V2(s) => { + IotaGasStatus::V1(s) => { display_info(f, s)?; per_object_storage_table(f, s)?; } @@ -25,7 +25,7 @@ impl<'a> Display for Pretty<'a, IotaGasStatus> { } } -fn per_object_storage_table(f: &mut Formatter, iota_gas_status: &GasStatusV2) -> std::fmt::Result { +fn per_object_storage_table(f: &mut Formatter, iota_gas_status: &GasStatusV1) -> std::fmt::Result { let mut builder = TableBuilder::default(); builder.push_record(vec!["Object ID", "Bytes", "Old Rebate", "New Rebate"]); for (object_id, per_obj_storage) in iota_gas_status.per_object_storage() { @@ -45,7 +45,7 @@ fn per_object_storage_table(f: &mut Formatter, iota_gas_status: &GasStatusV2) -> write!(f, "\n{}\n", table) } -fn display_info(f: &mut Formatter<'_>, iota_gas_status: &GasStatusV2) -> std::fmt::Result { +fn display_info(f: &mut Formatter<'_>, iota_gas_status: &GasStatusV1) -> std::fmt::Result { let mut builder = TableBuilder::default(); builder.push_record(vec!["Gas Info".to_string()]); builder.push_record(vec![format!( diff --git a/crates/iota-tool/src/commands.rs b/crates/iota-tool/src/commands.rs index ab139db7e78..7c4a03eabcb 100644 --- a/crates/iota-tool/src/commands.rs +++ b/crates/iota-tool/src/commands.rs @@ -639,6 +639,7 @@ impl ToolCommand { .handle_checkpoint(CheckpointRequest { sequence_number, request_content: true, + certified: true, }) .await .unwrap(); diff --git a/crates/iota-types/src/effects/effects_v1.rs b/crates/iota-types/src/effects/effects_v1.rs index ea26901b1a8..75210c4344b 100644 --- a/crates/iota-types/src/effects/effects_v1.rs +++ b/crates/iota-types/src/effects/effects_v1.rs @@ -2,24 +2,29 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use std::{ - collections::{BTreeMap, HashSet}, - fmt::{Display, Formatter, Write}, -}; +#[cfg(debug_assertions)] +use std::collections::HashSet; +use std::collections::{BTreeMap, BTreeSet}; use serde::{Deserialize, Serialize}; -use super::{IDOperation, ObjectChange}; +use super::{ + EffectsObjectChange, IDOperation, ObjectChange, + object_change::{ObjectIn, ObjectOut}, +}; +#[cfg(debug_assertions)] +use crate::is_system_package; use crate::{ base_types::{ - EpochId, IotaAddress, ObjectID, ObjectRef, SequenceNumber, TransactionDigest, - random_object_ref, + EpochId, IotaAddress, ObjectDigest, ObjectID, ObjectRef, SequenceNumber, TransactionDigest, + VersionDigest, }, - digests::{ObjectDigest, TransactionEventsDigest}, - effects::{InputSharedObject, TransactionEffectsAPI, UnchangedSharedKind}, + digests::{EffectsAuxDataDigest, TransactionEventsDigest}, + effects::{InputSharedObject, TransactionEffectsAPI}, + execution::SharedInput, execution_status::ExecutionStatus, gas::GasCostSummary, - object::Owner, + object::{OBJECT_START_VERSION, Owner}, }; /// The response from processing a transaction or a certified transaction @@ -30,102 +35,33 @@ pub struct TransactionEffectsV1 { /// The epoch when this transaction was executed. executed_epoch: EpochId, gas_used: GasCostSummary, - /// The version that every modified (mutated or deleted) object had before - /// it was modified by this transaction. - modified_at_versions: Vec<(ObjectID, SequenceNumber)>, - /// The object references of the shared objects used in this transaction. - /// Empty if no shared objects were used. - shared_objects: Vec, /// The transaction digest transaction_digest: TransactionDigest, - - // TODO: All the SequenceNumbers in the ObjectRefs below equal the same value (the lamport - // timestamp of the transaction). Consider factoring this out into one place in the effects. - /// ObjectRef and owner of new objects created. - created: Vec<(ObjectRef, Owner)>, - /// ObjectRef and owner of mutated objects, including gas object. - mutated: Vec<(ObjectRef, Owner)>, - /// ObjectRef and owner of objects that are unwrapped in this transaction. - /// Unwrapped objects are objects that were wrapped into other objects in - /// the past, and just got extracted out. - unwrapped: Vec<(ObjectRef, Owner)>, - /// Object Refs of objects now deleted (the new refs). - deleted: Vec, - /// Object refs of objects previously wrapped in other objects but now - /// deleted. - unwrapped_then_deleted: Vec, - /// Object refs of objects now wrapped in other objects. - wrapped: Vec, - /// The updated gas object reference. Have a dedicated field for convenient - /// access. It's also included in mutated. - gas_object: (ObjectRef, Owner), + /// The updated gas object reference, as an index into the `changed_objects` + /// vector. Having a dedicated field for convenient access. + /// System transaction that don't require gas will leave this as None. + gas_object_index: Option, /// The digest of the events emitted during execution, /// can be None if the transaction does not emit any event. events_digest: Option, /// The set of transaction digests this transaction depends on. dependencies: Vec, -} - -impl TransactionEffectsV1 { - pub fn new( - status: ExecutionStatus, - executed_epoch: EpochId, - gas_used: GasCostSummary, - modified_at_versions: Vec<(ObjectID, SequenceNumber)>, - shared_objects: Vec, - transaction_digest: TransactionDigest, - created: Vec<(ObjectRef, Owner)>, - mutated: Vec<(ObjectRef, Owner)>, - unwrapped: Vec<(ObjectRef, Owner)>, - deleted: Vec, - unwrapped_then_deleted: Vec, - wrapped: Vec, - gas_object: (ObjectRef, Owner), - events_digest: Option, - dependencies: Vec, - ) -> Self { - Self { - status, - executed_epoch, - gas_used, - modified_at_versions, - shared_objects, - transaction_digest, - created, - mutated, - unwrapped, - deleted, - unwrapped_then_deleted, - wrapped, - gas_object, - events_digest, - dependencies, - } - } - - pub fn modified_at_versions(&self) -> &[(ObjectID, SequenceNumber)] { - &self.modified_at_versions - } - - pub fn mutated(&self) -> &[(ObjectRef, Owner)] { - &self.mutated - } - - pub fn created(&self) -> &[(ObjectRef, Owner)] { - &self.created - } - pub fn unwrapped(&self) -> &[(ObjectRef, Owner)] { - &self.unwrapped - } - - pub fn deleted(&self) -> &[ObjectRef] { - &self.deleted - } - - pub fn wrapped(&self) -> &[ObjectRef] { - &self.wrapped - } + /// The version number of all the written Move objects by this transaction. + pub(crate) lamport_version: SequenceNumber, + /// Objects whose state are changed in the object store. + changed_objects: Vec<(ObjectID, EffectsObjectChange)>, + /// Shared objects that are not mutated in this transaction. Unlike owned + /// objects, read-only shared objects' version are not committed in the + /// transaction, and in order for a node to catch up and execute it + /// without consensus sequencing, the version needs to be committed in + /// the effects. + unchanged_shared_objects: Vec<(ObjectID, UnchangedSharedKind)>, + /// Auxiliary data that are not protocol-critical, generated as part of the + /// effects but are stored separately. Storing it separately allows us + /// to avoid bloating the effects with data that are not critical. + /// It also provides more flexibility on the format and type of the data. + aux_data_digest: Option, } impl TransactionEffectsAPI for TransactionEffectsV1 { @@ -142,127 +78,238 @@ impl TransactionEffectsAPI for TransactionEffectsV1 { } fn modified_at_versions(&self) -> Vec<(ObjectID, SequenceNumber)> { - self.modified_at_versions.clone() + self.changed_objects + .iter() + .filter_map(|(id, change)| { + if let ObjectIn::Exist(((version, _digest), _owner)) = &change.input_state { + Some((*id, *version)) + } else { + None + } + }) + .collect() } fn lamport_version(&self) -> SequenceNumber { - SequenceNumber::lamport_increment(self.modified_at_versions.iter().map(|(_, v)| *v)) + self.lamport_version } fn old_object_metadata(&self) -> Vec<(ObjectRef, Owner)> { - unimplemented!("Only supposed by v2 and above"); + self.changed_objects + .iter() + .filter_map(|(id, change)| { + if let ObjectIn::Exist(((version, digest), owner)) = &change.input_state { + Some(((*id, *version, *digest), *owner)) + } else { + None + } + }) + .collect() } fn input_shared_objects(&self) -> Vec { - let modified: HashSet<_> = self.modified_at_versions.iter().map(|(r, _)| r).collect(); - self.shared_objects + self.changed_objects .iter() - .map(|r| { - if modified.contains(&r.0) { - InputSharedObject::Mutate(*r) - } else { - InputSharedObject::ReadOnly(*r) + .filter_map(|(id, change)| match &change.input_state { + ObjectIn::Exist(((version, digest), Owner::Shared { .. })) => { + Some(InputSharedObject::Mutate((*id, *version, *digest))) } + _ => None, }) + .chain( + self.unchanged_shared_objects + .iter() + .filter_map(|(id, change_kind)| match change_kind { + UnchangedSharedKind::ReadOnlyRoot((version, digest)) => { + Some(InputSharedObject::ReadOnly((*id, *version, *digest))) + } + UnchangedSharedKind::MutateDeleted(seqno) => { + Some(InputSharedObject::MutateDeleted(*id, *seqno)) + } + UnchangedSharedKind::ReadDeleted(seqno) => { + Some(InputSharedObject::ReadDeleted(*id, *seqno)) + } + UnchangedSharedKind::Cancelled(seqno) => { + Some(InputSharedObject::Cancelled(*id, *seqno)) + } + // We can not expose the per epoch config object as input shared object, + // since it does not require sequencing, and hence shall not be considered + // as a normal input shared object. + UnchangedSharedKind::PerEpochConfig => None, + }), + ) .collect() } fn created(&self) -> Vec<(ObjectRef, Owner)> { - self.created.clone() + self.changed_objects + .iter() + .filter_map(|(id, change)| { + match ( + &change.input_state, + &change.output_state, + &change.id_operation, + ) { + ( + ObjectIn::NotExist, + ObjectOut::ObjectWrite((digest, owner)), + IDOperation::Created, + ) => Some(((*id, self.lamport_version, *digest), *owner)), + ( + ObjectIn::NotExist, + ObjectOut::PackageWrite((version, digest)), + IDOperation::Created, + ) => Some(((*id, *version, *digest), Owner::Immutable)), + _ => None, + } + }) + .collect() } fn mutated(&self) -> Vec<(ObjectRef, Owner)> { - self.mutated.clone() + self.changed_objects + .iter() + .filter_map( + |(id, change)| match (&change.input_state, &change.output_state) { + (ObjectIn::Exist(_), ObjectOut::ObjectWrite((digest, owner))) => { + Some(((*id, self.lamport_version, *digest), *owner)) + } + (ObjectIn::Exist(_), ObjectOut::PackageWrite((version, digest))) => { + Some(((*id, *version, *digest), Owner::Immutable)) + } + _ => None, + }, + ) + .collect() } fn unwrapped(&self) -> Vec<(ObjectRef, Owner)> { - self.unwrapped.clone() + self.changed_objects + .iter() + .filter_map(|(id, change)| { + match ( + &change.input_state, + &change.output_state, + &change.id_operation, + ) { + ( + ObjectIn::NotExist, + ObjectOut::ObjectWrite((digest, owner)), + IDOperation::None, + ) => Some(((*id, self.lamport_version, *digest), *owner)), + _ => None, + } + }) + .collect() } fn deleted(&self) -> Vec { - self.deleted.clone() + self.changed_objects + .iter() + .filter_map(|(id, change)| { + match ( + &change.input_state, + &change.output_state, + &change.id_operation, + ) { + (ObjectIn::Exist(_), ObjectOut::NotExist, IDOperation::Deleted) => Some(( + *id, + self.lamport_version, + ObjectDigest::OBJECT_DIGEST_DELETED, + )), + _ => None, + } + }) + .collect() } fn unwrapped_then_deleted(&self) -> Vec { - self.unwrapped_then_deleted.clone() + self.changed_objects + .iter() + .filter_map(|(id, change)| { + match ( + &change.input_state, + &change.output_state, + &change.id_operation, + ) { + (ObjectIn::NotExist, ObjectOut::NotExist, IDOperation::Deleted) => Some(( + *id, + self.lamport_version, + ObjectDigest::OBJECT_DIGEST_DELETED, + )), + _ => None, + } + }) + .collect() } fn wrapped(&self) -> Vec { - self.wrapped.clone() + self.changed_objects + .iter() + .filter_map(|(id, change)| { + match ( + &change.input_state, + &change.output_state, + &change.id_operation, + ) { + (ObjectIn::Exist(_), ObjectOut::NotExist, IDOperation::None) => Some(( + *id, + self.lamport_version, + ObjectDigest::OBJECT_DIGEST_WRAPPED, + )), + _ => None, + } + }) + .collect() } fn object_changes(&self) -> Vec { - let modified_at: BTreeMap<_, _> = self.modified_at_versions.iter().copied().collect(); - - let created = self.created.iter().map(|((id, v, d), _)| ObjectChange { - id: *id, - input_version: None, - input_digest: None, - output_version: Some(*v), - output_digest: Some(*d), - id_operation: IDOperation::Created, - }); - - let mutated = self.mutated.iter().map(|((id, v, d), _)| ObjectChange { - id: *id, - input_version: modified_at.get(id).copied(), - input_digest: None, - output_version: Some(*v), - output_digest: Some(*d), - id_operation: IDOperation::None, - }); - - let unwrapped = self.unwrapped.iter().map(|((id, v, d), _)| ObjectChange { - id: *id, - input_version: None, - input_digest: None, - output_version: Some(*v), - output_digest: Some(*d), - id_operation: IDOperation::None, - }); + self.changed_objects + .iter() + .map(|(id, change)| { + let input_version_digest = match &change.input_state { + ObjectIn::NotExist => None, + ObjectIn::Exist((vd, _)) => Some(*vd), + }; + + let output_version_digest = match &change.output_state { + ObjectOut::NotExist => None, + ObjectOut::ObjectWrite((d, _)) => Some((self.lamport_version, *d)), + ObjectOut::PackageWrite(vd) => Some(*vd), + }; + + ObjectChange { + id: *id, - let deleted = self.deleted.iter().map(|(id, _, _)| ObjectChange { - id: *id, - input_version: modified_at.get(id).copied(), - input_digest: None, - output_version: None, - output_digest: None, - id_operation: IDOperation::Deleted, - }); + input_version: input_version_digest.map(|k| k.0), + input_digest: input_version_digest.map(|k| k.1), - let unwrapped_then_deleted = - self.unwrapped_then_deleted - .iter() - .map(|(id, _, _)| ObjectChange { - id: *id, - input_version: None, - input_digest: None, - output_version: None, - output_digest: None, - id_operation: IDOperation::Deleted, - }); - - let wrapped = self.wrapped.iter().map(|(id, _, _)| ObjectChange { - id: *id, - input_version: modified_at.get(id).copied(), - input_digest: None, - output_version: None, - output_digest: None, - id_operation: IDOperation::None, - }); + output_version: output_version_digest.map(|k| k.0), + output_digest: output_version_digest.map(|k| k.1), - created - .chain(mutated) - .chain(unwrapped) - .chain(deleted) - .chain(unwrapped_then_deleted) - .chain(wrapped) + id_operation: change.id_operation, + } + }) .collect() } fn gas_object(&self) -> (ObjectRef, Owner) { - self.gas_object + if let Some(gas_object_index) = self.gas_object_index { + let entry = &self.changed_objects[gas_object_index as usize]; + match entry.1.output_state { + ObjectOut::ObjectWrite((digest, owner)) => { + ((entry.0, self.lamport_version, digest), owner) + } + _ => panic!("Gas object must be an ObjectWrite in changed_objects"), + } + } else { + ( + (ObjectID::ZERO, SequenceNumber::default(), ObjectDigest::MIN), + Owner::AddressOwner(IotaAddress::default()), + ) + } } + fn events_digest(&self) -> Option<&TransactionEventsDigest> { self.events_digest.as_ref() } @@ -280,16 +327,7 @@ impl TransactionEffectsAPI for TransactionEffectsV1 { } fn unchanged_shared_objects(&self) -> Vec<(ObjectID, UnchangedSharedKind)> { - self.input_shared_objects() - .iter() - .filter_map(|o| match o { - // In effects v1, the only unchanged shared objects are read-only shared objects. - InputSharedObject::ReadOnly(oref) => { - Some((oref.0, UnchangedSharedKind::ReadOnlyRoot((oref.1, oref.2)))) - } - _ => None, - }) - .collect() + self.unchanged_shared_objects.clone() } fn status_mut_for_testing(&mut self) -> &mut ExecutionStatus { @@ -311,96 +349,265 @@ impl TransactionEffectsAPI for TransactionEffectsV1 { fn unsafe_add_input_shared_object_for_testing(&mut self, kind: InputSharedObject) { match kind { InputSharedObject::Mutate(obj_ref) => { - self.shared_objects.push(obj_ref); - self.modified_at_versions.push((obj_ref.0, obj_ref.1)); - } - InputSharedObject::ReadOnly(obj_ref) => { - self.shared_objects.push(obj_ref); - } - InputSharedObject::ReadDeleted(id, version) - | InputSharedObject::MutateDeleted(id, version) => { - self.shared_objects - .push((id, version, ObjectDigest::OBJECT_DIGEST_DELETED)); - } - InputSharedObject::Cancelled(..) => { - panic!("Transaction cancellation is not supported in effect v1"); + self.changed_objects.push((obj_ref.0, EffectsObjectChange { + input_state: ObjectIn::Exist(((obj_ref.1, obj_ref.2), Owner::Shared { + initial_shared_version: OBJECT_START_VERSION, + })), + output_state: ObjectOut::ObjectWrite((obj_ref.2, Owner::Shared { + initial_shared_version: obj_ref.1, + })), + id_operation: IDOperation::None, + })) } + InputSharedObject::ReadOnly(obj_ref) => self.unchanged_shared_objects.push(( + obj_ref.0, + UnchangedSharedKind::ReadOnlyRoot((obj_ref.1, obj_ref.2)), + )), + InputSharedObject::ReadDeleted(obj_id, seqno) => self + .unchanged_shared_objects + .push((obj_id, UnchangedSharedKind::ReadDeleted(seqno))), + InputSharedObject::MutateDeleted(obj_id, seqno) => self + .unchanged_shared_objects + .push((obj_id, UnchangedSharedKind::MutateDeleted(seqno))), + InputSharedObject::Cancelled(obj_id, seqno) => self + .unchanged_shared_objects + .push((obj_id, UnchangedSharedKind::Cancelled(seqno))), } } - fn unsafe_add_deleted_live_object_for_testing(&mut self, object: ObjectRef) { - self.modified_at_versions.push((object.0, object.1)); + fn unsafe_add_deleted_live_object_for_testing(&mut self, obj_ref: ObjectRef) { + self.changed_objects.push((obj_ref.0, EffectsObjectChange { + input_state: ObjectIn::Exist(( + (obj_ref.1, obj_ref.2), + Owner::AddressOwner(IotaAddress::default()), + )), + output_state: ObjectOut::ObjectWrite(( + obj_ref.2, + Owner::AddressOwner(IotaAddress::default()), + )), + id_operation: IDOperation::None, + })) } - fn unsafe_add_object_tombstone_for_testing(&mut self, object: ObjectRef) { - self.deleted.push(object); + fn unsafe_add_object_tombstone_for_testing(&mut self, obj_ref: ObjectRef) { + self.changed_objects.push((obj_ref.0, EffectsObjectChange { + input_state: ObjectIn::Exist(( + (obj_ref.1, obj_ref.2), + Owner::AddressOwner(IotaAddress::default()), + )), + output_state: ObjectOut::NotExist, + id_operation: IDOperation::Deleted, + })) } } -impl Display for TransactionEffectsV1 { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let mut writer = String::new(); - writeln!(writer, "Status : {:?}", self.status)?; - if !self.created.is_empty() { - writeln!(writer, "Created Objects:")?; - for ((id, _, _), owner) in &self.created { - writeln!(writer, " - ID: {} , Owner: {}", id, owner)?; - } - } - if !self.mutated.is_empty() { - writeln!(writer, "Mutated Objects:")?; - for ((id, _, _), owner) in &self.mutated { - writeln!(writer, " - ID: {} , Owner: {}", id, owner)?; - } - } - if !self.deleted.is_empty() { - writeln!(writer, "Deleted Objects:")?; - for (id, _, _) in &self.deleted { - writeln!(writer, " - ID: {}", id)?; - } - } - if !self.wrapped.is_empty() { - writeln!(writer, "Wrapped Objects:")?; - for (id, _, _) in &self.wrapped { - writeln!(writer, " - ID: {}", id)?; +impl TransactionEffectsV1 { + pub fn new( + status: ExecutionStatus, + executed_epoch: EpochId, + gas_used: GasCostSummary, + shared_objects: Vec, + loaded_per_epoch_config_objects: BTreeSet, + transaction_digest: TransactionDigest, + lamport_version: SequenceNumber, + changed_objects: BTreeMap, + gas_object: Option, + events_digest: Option, + dependencies: Vec, + ) -> Self { + let unchanged_shared_objects = shared_objects + .into_iter() + .filter_map(|shared_input| match shared_input { + SharedInput::Existing((id, version, digest)) => { + if changed_objects.contains_key(&id) { + None + } else { + Some((id, UnchangedSharedKind::ReadOnlyRoot((version, digest)))) + } + } + SharedInput::Deleted((id, version, mutable, _)) => { + debug_assert!(!changed_objects.contains_key(&id)); + if mutable { + Some((id, UnchangedSharedKind::MutateDeleted(version))) + } else { + Some((id, UnchangedSharedKind::ReadDeleted(version))) + } + } + SharedInput::Cancelled((id, version)) => { + debug_assert!(!changed_objects.contains_key(&id)); + Some((id, UnchangedSharedKind::Cancelled(version))) + } + }) + .chain( + loaded_per_epoch_config_objects + .into_iter() + .map(|id| (id, UnchangedSharedKind::PerEpochConfig)), + ) + .collect(); + let changed_objects: Vec<_> = changed_objects.into_iter().collect(); + + let gas_object_index = gas_object.map(|gas_id| { + changed_objects + .iter() + .position(|(id, _)| id == &gas_id) + .unwrap() as u32 + }); + + #[allow(clippy::let_and_return)] + let result = Self { + status, + executed_epoch, + gas_used, + transaction_digest, + lamport_version, + changed_objects, + unchanged_shared_objects, + gas_object_index, + events_digest, + dependencies, + aux_data_digest: None, + }; + #[cfg(debug_assertions)] + result.check_invariant(); + + result + } + + /// This function demonstrates what's the invariant of the effects. + /// It also documents the semantics of different combinations in object + /// changes. + #[cfg(debug_assertions)] + fn check_invariant(&self) { + let mut unique_ids = HashSet::new(); + for (id, change) in &self.changed_objects { + assert!(unique_ids.insert(*id)); + match ( + &change.input_state, + &change.output_state, + &change.id_operation, + ) { + (ObjectIn::NotExist, ObjectOut::NotExist, IDOperation::Created) => { + // created and then wrapped Move object. + } + (ObjectIn::NotExist, ObjectOut::NotExist, IDOperation::Deleted) => { + // unwrapped and then deleted Move object. + } + (ObjectIn::NotExist, ObjectOut::ObjectWrite((_, owner)), IDOperation::None) => { + // unwrapped Move object. + // It's not allowed to make an object shared after unwrapping. + assert!(!owner.is_shared()); + } + (ObjectIn::NotExist, ObjectOut::ObjectWrite(..), IDOperation::Created) => { + // created Move object. + } + (ObjectIn::NotExist, ObjectOut::PackageWrite(_), IDOperation::Created) => { + // created Move package or user Move package upgrade. + } + ( + ObjectIn::Exist(((old_version, _), old_owner)), + ObjectOut::NotExist, + IDOperation::None, + ) => { + // wrapped. + assert!(old_version.value() < self.lamport_version.value()); + assert!( + !old_owner.is_shared() && !old_owner.is_immutable(), + "Cannot wrap shared or immutable object" + ); + } + ( + ObjectIn::Exist(((old_version, _), old_owner)), + ObjectOut::NotExist, + IDOperation::Deleted, + ) => { + // deleted. + assert!(old_version.value() < self.lamport_version.value()); + assert!(!old_owner.is_immutable(), "Cannot delete immutable object"); + } + ( + ObjectIn::Exist(((old_version, old_digest), old_owner)), + ObjectOut::ObjectWrite((new_digest, new_owner)), + IDOperation::None, + ) => { + // mutated. + assert!(old_version.value() < self.lamport_version.value()); + assert_ne!(old_digest, new_digest); + assert!(!old_owner.is_immutable(), "Cannot mutate immutable object"); + if old_owner.is_shared() { + assert!(new_owner.is_shared(), "Cannot un-share an object"); + } else { + assert!(!new_owner.is_shared(), "Cannot share an existing object"); + } + } + ( + ObjectIn::Exist(((old_version, old_digest), old_owner)), + ObjectOut::PackageWrite((new_version, new_digest)), + IDOperation::None, + ) => { + // system package upgrade. + assert!( + old_owner.is_immutable() && is_system_package(*id), + "Must be a system package" + ); + assert_eq!(old_version.value() + 1, new_version.value()); + assert_ne!(old_digest, new_digest); + } + _ => { + panic!("Impossible object change: {:?}, {:?}", id, change); + } } } - if !self.unwrapped.is_empty() { - writeln!(writer, "Unwrapped Objects:")?; - for ((id, _, _), owner) in &self.unwrapped { - writeln!(writer, " - ID: {} , Owner: {}", id, owner)?; - } + // Make sure that gas object exists in changed_objects. + let (_, owner) = self.gas_object(); + assert!(matches!(owner, Owner::AddressOwner(_))); + + for (id, _) in &self.unchanged_shared_objects { + assert!( + unique_ids.insert(*id), + "Duplicate object id: {:?}\n{:#?}", + id, + self + ); } - write!(f, "{}", writer) + } + + pub fn changed_objects(&self) -> &[(ObjectID, EffectsObjectChange)] { + &self.changed_objects } } impl Default for TransactionEffectsV1 { fn default() -> Self { - TransactionEffectsV1 { + Self { status: ExecutionStatus::Success, executed_epoch: 0, - gas_used: GasCostSummary { - computation_cost: 0, - storage_cost: 0, - storage_rebate: 0, - non_refundable_storage_fee: 0, - }, - modified_at_versions: Vec::new(), - shared_objects: Vec::new(), - transaction_digest: TransactionDigest::random(), - created: Vec::new(), - mutated: Vec::new(), - unwrapped: Vec::new(), - deleted: Vec::new(), - unwrapped_then_deleted: Vec::new(), - wrapped: Vec::new(), - gas_object: ( - random_object_ref(), - Owner::AddressOwner(IotaAddress::default()), - ), + gas_used: GasCostSummary::default(), + transaction_digest: TransactionDigest::default(), + lamport_version: SequenceNumber::default(), + changed_objects: vec![], + unchanged_shared_objects: vec![], + gas_object_index: None, events_digest: None, - dependencies: Vec::new(), + dependencies: vec![], + aux_data_digest: None, } } } + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +pub enum UnchangedSharedKind { + /// Read-only shared objects from the input. We don't really need + /// ObjectDigest for protocol correctness, but it will make it easier to + /// verify untrusted read. + ReadOnlyRoot(VersionDigest), + /// Deleted shared objects that appear mutably/owned in the input. + MutateDeleted(SequenceNumber), + /// Deleted shared objects that appear as read-only in the input. + ReadDeleted(SequenceNumber), + /// Shared objects in cancelled transaction. The sequence number embed + /// cancellation reason. + Cancelled(SequenceNumber), + /// Read of a per-epoch config object that should remain the same during an + /// epoch. + PerEpochConfig, +} diff --git a/crates/iota-types/src/effects/effects_v2.rs b/crates/iota-types/src/effects/effects_v2.rs deleted file mode 100644 index 68184453467..00000000000 --- a/crates/iota-types/src/effects/effects_v2.rs +++ /dev/null @@ -1,613 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// Modifications Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -#[cfg(debug_assertions)] -use std::collections::HashSet; -use std::collections::{BTreeMap, BTreeSet}; - -use serde::{Deserialize, Serialize}; - -use super::{ - EffectsObjectChange, IDOperation, ObjectChange, - object_change::{ObjectIn, ObjectOut}, -}; -#[cfg(debug_assertions)] -use crate::is_system_package; -use crate::{ - base_types::{ - EpochId, IotaAddress, ObjectDigest, ObjectID, ObjectRef, SequenceNumber, TransactionDigest, - VersionDigest, - }, - digests::{EffectsAuxDataDigest, TransactionEventsDigest}, - effects::{InputSharedObject, TransactionEffectsAPI}, - execution::SharedInput, - execution_status::ExecutionStatus, - gas::GasCostSummary, - object::{OBJECT_START_VERSION, Owner}, -}; - -/// The response from processing a transaction or a certified transaction -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub struct TransactionEffectsV2 { - /// The status of the execution - status: ExecutionStatus, - /// The epoch when this transaction was executed. - executed_epoch: EpochId, - gas_used: GasCostSummary, - /// The transaction digest - transaction_digest: TransactionDigest, - /// The updated gas object reference, as an index into the `changed_objects` - /// vector. Having a dedicated field for convenient access. - /// System transaction that don't require gas will leave this as None. - gas_object_index: Option, - /// The digest of the events emitted during execution, - /// can be None if the transaction does not emit any event. - events_digest: Option, - /// The set of transaction digests this transaction depends on. - dependencies: Vec, - - /// The version number of all the written Move objects by this transaction. - pub(crate) lamport_version: SequenceNumber, - /// Objects whose state are changed in the object store. - changed_objects: Vec<(ObjectID, EffectsObjectChange)>, - /// Shared objects that are not mutated in this transaction. Unlike owned - /// objects, read-only shared objects' version are not committed in the - /// transaction, and in order for a node to catch up and execute it - /// without consensus sequencing, the version needs to be committed in - /// the effects. - unchanged_shared_objects: Vec<(ObjectID, UnchangedSharedKind)>, - /// Auxiliary data that are not protocol-critical, generated as part of the - /// effects but are stored separately. Storing it separately allows us - /// to avoid bloating the effects with data that are not critical. - /// It also provides more flexibility on the format and type of the data. - aux_data_digest: Option, -} - -impl TransactionEffectsAPI for TransactionEffectsV2 { - fn status(&self) -> &ExecutionStatus { - &self.status - } - - fn into_status(self) -> ExecutionStatus { - self.status - } - - fn executed_epoch(&self) -> EpochId { - self.executed_epoch - } - - fn modified_at_versions(&self) -> Vec<(ObjectID, SequenceNumber)> { - self.changed_objects - .iter() - .filter_map(|(id, change)| { - if let ObjectIn::Exist(((version, _digest), _owner)) = &change.input_state { - Some((*id, *version)) - } else { - None - } - }) - .collect() - } - - fn lamport_version(&self) -> SequenceNumber { - self.lamport_version - } - - fn old_object_metadata(&self) -> Vec<(ObjectRef, Owner)> { - self.changed_objects - .iter() - .filter_map(|(id, change)| { - if let ObjectIn::Exist(((version, digest), owner)) = &change.input_state { - Some(((*id, *version, *digest), *owner)) - } else { - None - } - }) - .collect() - } - - fn input_shared_objects(&self) -> Vec { - self.changed_objects - .iter() - .filter_map(|(id, change)| match &change.input_state { - ObjectIn::Exist(((version, digest), Owner::Shared { .. })) => { - Some(InputSharedObject::Mutate((*id, *version, *digest))) - } - _ => None, - }) - .chain( - self.unchanged_shared_objects - .iter() - .filter_map(|(id, change_kind)| match change_kind { - UnchangedSharedKind::ReadOnlyRoot((version, digest)) => { - Some(InputSharedObject::ReadOnly((*id, *version, *digest))) - } - UnchangedSharedKind::MutateDeleted(seqno) => { - Some(InputSharedObject::MutateDeleted(*id, *seqno)) - } - UnchangedSharedKind::ReadDeleted(seqno) => { - Some(InputSharedObject::ReadDeleted(*id, *seqno)) - } - UnchangedSharedKind::Cancelled(seqno) => { - Some(InputSharedObject::Cancelled(*id, *seqno)) - } - // We can not expose the per epoch config object as input shared object, - // since it does not require sequencing, and hence shall not be considered - // as a normal input shared object. - UnchangedSharedKind::PerEpochConfig => None, - }), - ) - .collect() - } - - fn created(&self) -> Vec<(ObjectRef, Owner)> { - self.changed_objects - .iter() - .filter_map(|(id, change)| { - match ( - &change.input_state, - &change.output_state, - &change.id_operation, - ) { - ( - ObjectIn::NotExist, - ObjectOut::ObjectWrite((digest, owner)), - IDOperation::Created, - ) => Some(((*id, self.lamport_version, *digest), *owner)), - ( - ObjectIn::NotExist, - ObjectOut::PackageWrite((version, digest)), - IDOperation::Created, - ) => Some(((*id, *version, *digest), Owner::Immutable)), - _ => None, - } - }) - .collect() - } - - fn mutated(&self) -> Vec<(ObjectRef, Owner)> { - self.changed_objects - .iter() - .filter_map( - |(id, change)| match (&change.input_state, &change.output_state) { - (ObjectIn::Exist(_), ObjectOut::ObjectWrite((digest, owner))) => { - Some(((*id, self.lamport_version, *digest), *owner)) - } - (ObjectIn::Exist(_), ObjectOut::PackageWrite((version, digest))) => { - Some(((*id, *version, *digest), Owner::Immutable)) - } - _ => None, - }, - ) - .collect() - } - - fn unwrapped(&self) -> Vec<(ObjectRef, Owner)> { - self.changed_objects - .iter() - .filter_map(|(id, change)| { - match ( - &change.input_state, - &change.output_state, - &change.id_operation, - ) { - ( - ObjectIn::NotExist, - ObjectOut::ObjectWrite((digest, owner)), - IDOperation::None, - ) => Some(((*id, self.lamport_version, *digest), *owner)), - _ => None, - } - }) - .collect() - } - - fn deleted(&self) -> Vec { - self.changed_objects - .iter() - .filter_map(|(id, change)| { - match ( - &change.input_state, - &change.output_state, - &change.id_operation, - ) { - (ObjectIn::Exist(_), ObjectOut::NotExist, IDOperation::Deleted) => Some(( - *id, - self.lamport_version, - ObjectDigest::OBJECT_DIGEST_DELETED, - )), - _ => None, - } - }) - .collect() - } - - fn unwrapped_then_deleted(&self) -> Vec { - self.changed_objects - .iter() - .filter_map(|(id, change)| { - match ( - &change.input_state, - &change.output_state, - &change.id_operation, - ) { - (ObjectIn::NotExist, ObjectOut::NotExist, IDOperation::Deleted) => Some(( - *id, - self.lamport_version, - ObjectDigest::OBJECT_DIGEST_DELETED, - )), - _ => None, - } - }) - .collect() - } - - fn wrapped(&self) -> Vec { - self.changed_objects - .iter() - .filter_map(|(id, change)| { - match ( - &change.input_state, - &change.output_state, - &change.id_operation, - ) { - (ObjectIn::Exist(_), ObjectOut::NotExist, IDOperation::None) => Some(( - *id, - self.lamport_version, - ObjectDigest::OBJECT_DIGEST_WRAPPED, - )), - _ => None, - } - }) - .collect() - } - - fn object_changes(&self) -> Vec { - self.changed_objects - .iter() - .map(|(id, change)| { - let input_version_digest = match &change.input_state { - ObjectIn::NotExist => None, - ObjectIn::Exist((vd, _)) => Some(*vd), - }; - - let output_version_digest = match &change.output_state { - ObjectOut::NotExist => None, - ObjectOut::ObjectWrite((d, _)) => Some((self.lamport_version, *d)), - ObjectOut::PackageWrite(vd) => Some(*vd), - }; - - ObjectChange { - id: *id, - - input_version: input_version_digest.map(|k| k.0), - input_digest: input_version_digest.map(|k| k.1), - - output_version: output_version_digest.map(|k| k.0), - output_digest: output_version_digest.map(|k| k.1), - - id_operation: change.id_operation, - } - }) - .collect() - } - - fn gas_object(&self) -> (ObjectRef, Owner) { - if let Some(gas_object_index) = self.gas_object_index { - let entry = &self.changed_objects[gas_object_index as usize]; - match entry.1.output_state { - ObjectOut::ObjectWrite((digest, owner)) => { - ((entry.0, self.lamport_version, digest), owner) - } - _ => panic!("Gas object must be an ObjectWrite in changed_objects"), - } - } else { - ( - (ObjectID::ZERO, SequenceNumber::default(), ObjectDigest::MIN), - Owner::AddressOwner(IotaAddress::default()), - ) - } - } - - fn events_digest(&self) -> Option<&TransactionEventsDigest> { - self.events_digest.as_ref() - } - - fn dependencies(&self) -> &[TransactionDigest] { - &self.dependencies - } - - fn transaction_digest(&self) -> &TransactionDigest { - &self.transaction_digest - } - - fn gas_cost_summary(&self) -> &GasCostSummary { - &self.gas_used - } - - fn unchanged_shared_objects(&self) -> Vec<(ObjectID, UnchangedSharedKind)> { - self.unchanged_shared_objects.clone() - } - - fn status_mut_for_testing(&mut self) -> &mut ExecutionStatus { - &mut self.status - } - - fn gas_cost_summary_mut_for_testing(&mut self) -> &mut GasCostSummary { - &mut self.gas_used - } - - fn transaction_digest_mut_for_testing(&mut self) -> &mut TransactionDigest { - &mut self.transaction_digest - } - - fn dependencies_mut_for_testing(&mut self) -> &mut Vec { - &mut self.dependencies - } - - fn unsafe_add_input_shared_object_for_testing(&mut self, kind: InputSharedObject) { - match kind { - InputSharedObject::Mutate(obj_ref) => { - self.changed_objects.push((obj_ref.0, EffectsObjectChange { - input_state: ObjectIn::Exist(((obj_ref.1, obj_ref.2), Owner::Shared { - initial_shared_version: OBJECT_START_VERSION, - })), - output_state: ObjectOut::ObjectWrite((obj_ref.2, Owner::Shared { - initial_shared_version: obj_ref.1, - })), - id_operation: IDOperation::None, - })) - } - InputSharedObject::ReadOnly(obj_ref) => self.unchanged_shared_objects.push(( - obj_ref.0, - UnchangedSharedKind::ReadOnlyRoot((obj_ref.1, obj_ref.2)), - )), - InputSharedObject::ReadDeleted(obj_id, seqno) => self - .unchanged_shared_objects - .push((obj_id, UnchangedSharedKind::ReadDeleted(seqno))), - InputSharedObject::MutateDeleted(obj_id, seqno) => self - .unchanged_shared_objects - .push((obj_id, UnchangedSharedKind::MutateDeleted(seqno))), - InputSharedObject::Cancelled(obj_id, seqno) => self - .unchanged_shared_objects - .push((obj_id, UnchangedSharedKind::Cancelled(seqno))), - } - } - - fn unsafe_add_deleted_live_object_for_testing(&mut self, obj_ref: ObjectRef) { - self.changed_objects.push((obj_ref.0, EffectsObjectChange { - input_state: ObjectIn::Exist(( - (obj_ref.1, obj_ref.2), - Owner::AddressOwner(IotaAddress::default()), - )), - output_state: ObjectOut::ObjectWrite(( - obj_ref.2, - Owner::AddressOwner(IotaAddress::default()), - )), - id_operation: IDOperation::None, - })) - } - - fn unsafe_add_object_tombstone_for_testing(&mut self, obj_ref: ObjectRef) { - self.changed_objects.push((obj_ref.0, EffectsObjectChange { - input_state: ObjectIn::Exist(( - (obj_ref.1, obj_ref.2), - Owner::AddressOwner(IotaAddress::default()), - )), - output_state: ObjectOut::NotExist, - id_operation: IDOperation::Deleted, - })) - } -} - -impl TransactionEffectsV2 { - pub fn new( - status: ExecutionStatus, - executed_epoch: EpochId, - gas_used: GasCostSummary, - shared_objects: Vec, - loaded_per_epoch_config_objects: BTreeSet, - transaction_digest: TransactionDigest, - lamport_version: SequenceNumber, - changed_objects: BTreeMap, - gas_object: Option, - events_digest: Option, - dependencies: Vec, - ) -> Self { - let unchanged_shared_objects = shared_objects - .into_iter() - .filter_map(|shared_input| match shared_input { - SharedInput::Existing((id, version, digest)) => { - if changed_objects.contains_key(&id) { - None - } else { - Some((id, UnchangedSharedKind::ReadOnlyRoot((version, digest)))) - } - } - SharedInput::Deleted((id, version, mutable, _)) => { - debug_assert!(!changed_objects.contains_key(&id)); - if mutable { - Some((id, UnchangedSharedKind::MutateDeleted(version))) - } else { - Some((id, UnchangedSharedKind::ReadDeleted(version))) - } - } - SharedInput::Cancelled((id, version)) => { - debug_assert!(!changed_objects.contains_key(&id)); - Some((id, UnchangedSharedKind::Cancelled(version))) - } - }) - .chain( - loaded_per_epoch_config_objects - .into_iter() - .map(|id| (id, UnchangedSharedKind::PerEpochConfig)), - ) - .collect(); - let changed_objects: Vec<_> = changed_objects.into_iter().collect(); - - let gas_object_index = gas_object.map(|gas_id| { - changed_objects - .iter() - .position(|(id, _)| id == &gas_id) - .unwrap() as u32 - }); - - #[allow(clippy::let_and_return)] - let result = Self { - status, - executed_epoch, - gas_used, - transaction_digest, - lamport_version, - changed_objects, - unchanged_shared_objects, - gas_object_index, - events_digest, - dependencies, - aux_data_digest: None, - }; - #[cfg(debug_assertions)] - result.check_invariant(); - - result - } - - /// This function demonstrates what's the invariant of the effects. - /// It also documents the semantics of different combinations in object - /// changes. - #[cfg(debug_assertions)] - fn check_invariant(&self) { - let mut unique_ids = HashSet::new(); - for (id, change) in &self.changed_objects { - assert!(unique_ids.insert(*id)); - match ( - &change.input_state, - &change.output_state, - &change.id_operation, - ) { - (ObjectIn::NotExist, ObjectOut::NotExist, IDOperation::Created) => { - // created and then wrapped Move object. - } - (ObjectIn::NotExist, ObjectOut::NotExist, IDOperation::Deleted) => { - // unwrapped and then deleted Move object. - } - (ObjectIn::NotExist, ObjectOut::ObjectWrite((_, owner)), IDOperation::None) => { - // unwrapped Move object. - // It's not allowed to make an object shared after unwrapping. - assert!(!owner.is_shared()); - } - (ObjectIn::NotExist, ObjectOut::ObjectWrite(..), IDOperation::Created) => { - // created Move object. - } - (ObjectIn::NotExist, ObjectOut::PackageWrite(_), IDOperation::Created) => { - // created Move package or user Move package upgrade. - } - ( - ObjectIn::Exist(((old_version, _), old_owner)), - ObjectOut::NotExist, - IDOperation::None, - ) => { - // wrapped. - assert!(old_version.value() < self.lamport_version.value()); - assert!( - !old_owner.is_shared() && !old_owner.is_immutable(), - "Cannot wrap shared or immutable object" - ); - } - ( - ObjectIn::Exist(((old_version, _), old_owner)), - ObjectOut::NotExist, - IDOperation::Deleted, - ) => { - // deleted. - assert!(old_version.value() < self.lamport_version.value()); - assert!(!old_owner.is_immutable(), "Cannot delete immutable object"); - } - ( - ObjectIn::Exist(((old_version, old_digest), old_owner)), - ObjectOut::ObjectWrite((new_digest, new_owner)), - IDOperation::None, - ) => { - // mutated. - assert!(old_version.value() < self.lamport_version.value()); - assert_ne!(old_digest, new_digest); - assert!(!old_owner.is_immutable(), "Cannot mutate immutable object"); - if old_owner.is_shared() { - assert!(new_owner.is_shared(), "Cannot un-share an object"); - } else { - assert!(!new_owner.is_shared(), "Cannot share an existing object"); - } - } - ( - ObjectIn::Exist(((old_version, old_digest), old_owner)), - ObjectOut::PackageWrite((new_version, new_digest)), - IDOperation::None, - ) => { - // system package upgrade. - assert!( - old_owner.is_immutable() && is_system_package(*id), - "Must be a system package" - ); - assert_eq!(old_version.value() + 1, new_version.value()); - assert_ne!(old_digest, new_digest); - } - _ => { - panic!("Impossible object change: {:?}, {:?}", id, change); - } - } - } - // Make sure that gas object exists in changed_objects. - let (_, owner) = self.gas_object(); - assert!(matches!(owner, Owner::AddressOwner(_))); - - for (id, _) in &self.unchanged_shared_objects { - assert!( - unique_ids.insert(*id), - "Duplicate object id: {:?}\n{:#?}", - id, - self - ); - } - } - - pub fn changed_objects(&self) -> &[(ObjectID, EffectsObjectChange)] { - &self.changed_objects - } -} - -impl Default for TransactionEffectsV2 { - fn default() -> Self { - Self { - status: ExecutionStatus::Success, - executed_epoch: 0, - gas_used: GasCostSummary::default(), - transaction_digest: TransactionDigest::default(), - lamport_version: SequenceNumber::default(), - changed_objects: vec![], - unchanged_shared_objects: vec![], - gas_object_index: None, - events_digest: None, - dependencies: vec![], - aux_data_digest: None, - } - } -} - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub enum UnchangedSharedKind { - /// Read-only shared objects from the input. We don't really need - /// ObjectDigest for protocol correctness, but it will make it easier to - /// verify untrusted read. - ReadOnlyRoot(VersionDigest), - /// Deleted shared objects that appear mutably/owned in the input. - MutateDeleted(SequenceNumber), - /// Deleted shared objects that appear as read-only in the input. - ReadDeleted(SequenceNumber), - /// Shared objects in cancelled transaction. The sequence number embed - /// cancellation reason. - Cancelled(SequenceNumber), - /// Read of a per-epoch config object that should remain the same during an - /// epoch. - PerEpochConfig, -} diff --git a/crates/iota-types/src/effects/mod.rs b/crates/iota-types/src/effects/mod.rs index 8d9b507562c..24f7f528259 100644 --- a/crates/iota-types/src/effects/mod.rs +++ b/crates/iota-types/src/effects/mod.rs @@ -5,14 +5,13 @@ use std::collections::{BTreeMap, BTreeSet}; use effects_v1::TransactionEffectsV1; -pub use effects_v2::UnchangedSharedKind; +pub use effects_v1::UnchangedSharedKind; use enum_dispatch::enum_dispatch; pub use object_change::{EffectsObjectChange, ObjectIn, ObjectOut}; use serde::{Deserialize, Serialize}; use shared_crypto::intent::{Intent, IntentScope}; pub use test_effects_builder::TestEffectsBuilder; -use self::effects_v2::TransactionEffectsV2; use crate::{ base_types::{ExecutionDigests, ObjectID, ObjectRef, SequenceNumber}, committee::{Committee, EpochId}, @@ -32,7 +31,6 @@ use crate::{ }; mod effects_v1; -mod effects_v2; mod object_change; mod test_effects_builder; @@ -59,7 +57,6 @@ pub const APPROX_SIZE_OF_OWNER: usize = 48; #[allow(clippy::large_enum_variant)] pub enum TransactionEffects { V1(TransactionEffectsV1), - V2(TransactionEffectsV2), } impl Message for TransactionEffects { @@ -74,7 +71,7 @@ impl Message for TransactionEffects { // TODO: Get rid of this and use TestEffectsBuilder instead. impl Default for TransactionEffects { fn default() -> Self { - TransactionEffects::V2(Default::default()) + TransactionEffects::V1(Default::default()) } } @@ -87,44 +84,6 @@ impl TransactionEffects { /// Creates a TransactionEffects message from the results of execution, /// choosing the correct format for the current protocol version. pub fn new_from_execution_v1( - status: ExecutionStatus, - executed_epoch: EpochId, - gas_used: GasCostSummary, - modified_at_versions: Vec<(ObjectID, SequenceNumber)>, - shared_objects: Vec, - transaction_digest: TransactionDigest, - created: Vec<(ObjectRef, Owner)>, - mutated: Vec<(ObjectRef, Owner)>, - unwrapped: Vec<(ObjectRef, Owner)>, - deleted: Vec, - unwrapped_then_deleted: Vec, - wrapped: Vec, - gas_object: (ObjectRef, Owner), - events_digest: Option, - dependencies: Vec, - ) -> Self { - Self::V1(TransactionEffectsV1::new( - status, - executed_epoch, - gas_used, - modified_at_versions, - shared_objects, - transaction_digest, - created, - mutated, - unwrapped, - deleted, - unwrapped_then_deleted, - wrapped, - gas_object, - events_digest, - dependencies, - )) - } - - /// Creates a TransactionEffects message from the results of execution, - /// choosing the correct format for the current protocol version. - pub fn new_from_execution_v2( status: ExecutionStatus, executed_epoch: EpochId, gas_used: GasCostSummary, @@ -137,7 +96,7 @@ impl TransactionEffects { events_digest: Option, dependencies: Vec, ) -> Self { - Self::V2(TransactionEffectsV2::new( + Self::V1(TransactionEffectsV1::new( status, executed_epoch, gas_used, @@ -160,30 +119,6 @@ impl TransactionEffects { } pub fn estimate_effects_size_upperbound_v1( - num_writes: usize, - num_mutables: usize, - num_deletes: usize, - num_deps: usize, - ) -> usize { - let fixed_sizes = APPROX_SIZE_OF_EXECUTION_STATUS - + APPROX_SIZE_OF_EPOCH_ID - + APPROX_SIZE_OF_GAS_COST_SUMMARY - + APPROX_SIZE_OF_OPT_TX_EVENTS_DIGEST; - - // Each write or delete contributes at roughly this amount because: - // Each write can be a mutation which can show up in `mutated` and - // `modified_at_versions` `num_delete` is added for padding - let approx_change_entry_size = 1_000 - + (APPROX_SIZE_OF_OWNER + APPROX_SIZE_OF_OBJECT_REF) * num_writes - + (APPROX_SIZE_OF_OBJECT_REF * num_mutables) - + (APPROX_SIZE_OF_OBJECT_REF * num_deletes); - - let deps_size = 1_000 + APPROX_SIZE_OF_TX_DIGEST * num_deps; - - fixed_sizes + approx_change_entry_size + deps_size - } - - pub fn estimate_effects_size_upperbound_v2( num_writes: usize, num_modifies: usize, num_deps: usize, @@ -317,7 +252,7 @@ pub trait TransactionEffectsAPI { /// Metadata of objects prior to modification. This includes any object that /// exists in the store prior to this transaction and is modified in /// this transaction. It includes objects that are mutated, wrapped and - /// deleted. This API is only available on effects v2 and above. + /// deleted. fn old_object_metadata(&self) -> Vec<(ObjectRef, Owner)>; /// Returns the list of sequenced shared objects used in the input. /// This is needed in effects because in transaction we only have object ID diff --git a/crates/iota-types/src/effects/test_effects_builder.rs b/crates/iota-types/src/effects/test_effects_builder.rs index 8ddf8d51717..4bc63afdd88 100644 --- a/crates/iota-types/src/effects/test_effects_builder.rs +++ b/crates/iota-types/src/effects/test_effects_builder.rs @@ -134,7 +134,7 @@ impl TestEffectsBuilder { let gas_object_id = self.transaction.transaction_data().gas()[0].0; let event_digest = self.events_digest; let dependencies = vec![]; - TransactionEffects::new_from_execution_v2( + TransactionEffects::new_from_execution_v1( status, executed_epoch, GasCostSummary::default(), diff --git a/crates/iota-types/src/execution.rs b/crates/iota-types/src/execution.rs index d7dadb98fb2..abbc6c69ee3 100644 --- a/crates/iota-types/src/execution.rs +++ b/crates/iota-types/src/execution.rs @@ -14,7 +14,7 @@ use crate::{ event::Event, is_system_package, object::{Data, Object, Owner}, - storage::{BackingPackageStore, ObjectChange}, + storage::BackingPackageStore, transaction::Argument, }; @@ -56,20 +56,13 @@ impl TypeLayoutStore for T where T: BackingPackageStore {} #[derive(Debug)] pub enum ExecutionResults { V1(ExecutionResultsV1), - V2(ExecutionResultsV2), -} - -#[derive(Debug)] -pub struct ExecutionResultsV1 { - pub object_changes: BTreeMap, - pub user_events: Vec, } /// Used by iota-execution v1 and above, to capture the execution results from /// Move. The results represent the primitive information that can then be used -/// to construct both transaction effects V1 and V2. +/// to construct both transaction effect V1. #[derive(Debug, Default)] -pub struct ExecutionResultsV2 { +pub struct ExecutionResultsV1 { /// All objects written regardless of whether they were mutated, created, or /// unwrapped. pub written_objects: BTreeMap, @@ -94,7 +87,7 @@ pub type ExecutionResult = ( Vec<(Vec, TypeTag)>, ); -impl ExecutionResultsV2 { +impl ExecutionResultsV1 { pub fn drop_writes(&mut self) { self.written_objects.clear(); self.modified_objects.clear(); diff --git a/crates/iota-types/src/full_checkpoint_content.rs b/crates/iota-types/src/full_checkpoint_content.rs index cd8c5bbf299..db44a808589 100644 --- a/crates/iota-types/src/full_checkpoint_content.rs +++ b/crates/iota-types/src/full_checkpoint_content.rs @@ -4,7 +4,6 @@ use std::collections::BTreeMap; -use itertools::Either; use serde::{Deserialize, Serialize}; use tap::Pipe; @@ -95,25 +94,8 @@ impl CheckpointTransaction { pub fn removed_objects_pre_version(&self) -> impl Iterator { // Iterator over id and versions for all deleted or wrapped objects match &self.effects { - TransactionEffects::V1(v1) => Either::Left( - // Effects v1 has deleted and wrapped objects versions as the "new" version, not - // the old one that was actually removed. So we need to take these - // and then look them up in the `modified_at_versions`. - // No need to chain unwrapped_then_deleted because these objects must have been - // wrapped before the transaction, hence they will not be in - // modified_at_versions / input_objects. - v1.deleted().iter().chain(v1.wrapped()).map(|(id, _, _)| { - // lookup the old version for mutated objects - let (_, old_version) = v1 - .modified_at_versions() - .iter() - .find(|(oid, _old_version)| oid == id) - .expect("deleted/wrapped object must have entry in 'modified_at_versions'"); - (id, old_version) - }), - ), - TransactionEffects::V2(v2) => { - Either::Right(v2.changed_objects().iter().filter_map(|(id, change)| { + TransactionEffects::V1(v1) => { + v1.changed_objects().iter().filter_map(|(id, change)| { match ( &change.input_state, &change.output_state, @@ -134,7 +116,7 @@ impl CheckpointTransaction { ) => Some((id, version)), _ => None, } - })) + }) } } // Use id and version to lookup in input Objects @@ -156,24 +138,8 @@ impl CheckpointTransaction { pub fn changed_objects(&self) -> impl Iterator)> { // Iterator over ((ObjectId, new version), Option) match &self.effects { - TransactionEffects::V1(v1) => Either::Left( - v1.created() - .iter() - .chain(v1.unwrapped()) - .map(|((id, version, _), _)| ((id, version), None)) - .chain(v1.mutated().iter().map(|((id, version, _), _)| { - // lookup the old version for mutated objects - let (_, old_version) = v1 - .modified_at_versions() - .iter() - .find(|(oid, _old_version)| oid == id) - .expect("mutated object must have entry in modified_at_versions"); - - ((id, version), Some(old_version)) - })), - ), - TransactionEffects::V2(v2) => { - Either::Right(v2.changed_objects().iter().filter_map(|(id, change)| { + TransactionEffects::V1(v1) => { + v1.changed_objects().iter().filter_map(|(id, change)| { match ( &change.input_state, &change.output_state, @@ -181,7 +147,7 @@ impl CheckpointTransaction { ) { // Created Objects (ObjectIn::NotExist, ObjectOut::ObjectWrite(_), IDOperation::Created) => { - Some(((id, &v2.lamport_version), None)) + Some(((id, &v1.lamport_version), None)) } ( ObjectIn::NotExist, @@ -191,12 +157,12 @@ impl CheckpointTransaction { // Unwrapped Objects (ObjectIn::NotExist, ObjectOut::ObjectWrite(_), IDOperation::None) => { - Some(((id, &v2.lamport_version), None)) + Some(((id, &v1.lamport_version), None)) } // Mutated Objects (ObjectIn::Exist(((old_version, _), _)), ObjectOut::ObjectWrite(_), _) => { - Some(((id, &v2.lamport_version), Some(old_version))) + Some(((id, &v1.lamport_version), Some(old_version))) } ( ObjectIn::Exist(((old_version, _), _)), @@ -206,7 +172,7 @@ impl CheckpointTransaction { _ => None, } - })) + }) } } // Lookup Objects in output Objects as well as old versions for mutated objects @@ -231,13 +197,8 @@ impl CheckpointTransaction { pub fn created_objects(&self) -> impl Iterator { // Iterator over (ObjectId, version) for created objects match &self.effects { - TransactionEffects::V1(v1) => Either::Left( - v1.created() - .iter() - .map(|((id, version, _), _)| (id, version)), - ), - TransactionEffects::V2(v2) => { - Either::Right(v2.changed_objects().iter().filter_map(|(id, change)| { + TransactionEffects::V1(v1) => { + v1.changed_objects().iter().filter_map(|(id, change)| { match ( &change.input_state, &change.output_state, @@ -245,7 +206,7 @@ impl CheckpointTransaction { ) { // Created Objects (ObjectIn::NotExist, ObjectOut::ObjectWrite(_), IDOperation::Created) => { - Some((id, &v2.lamport_version)) + Some((id, &v1.lamport_version)) } ( ObjectIn::NotExist, @@ -255,7 +216,7 @@ impl CheckpointTransaction { _ => None, } - })) + }) } } // Lookup Objects in output Objects as well as old versions for mutated objects diff --git a/crates/iota-types/src/gas.rs b/crates/iota-types/src/gas.rs index 9cad8bdf882..39b7bd9edff 100644 --- a/crates/iota-types/src/gas.rs +++ b/crates/iota-types/src/gas.rs @@ -20,7 +20,7 @@ pub mod checked { effects::{TransactionEffects, TransactionEffectsAPI}, error::{ExecutionError, IotaResult, UserInputError, UserInputResult}, gas_model::{ - gas_predicates::gas_price_too_high, gas_v2::IotaGasStatus as IotaGasStatusV2, + gas_predicates::gas_price_too_high, gas_v1::IotaGasStatus as IotaGasStatusV1, tables::GasStatus, }, iota_serde::{BigInt, Readable}, @@ -57,9 +57,7 @@ pub mod checked { #[enum_dispatch(IotaGasStatusAPI)] #[derive(Debug)] pub enum IotaGasStatus { - // V1 does not exists any longer as it was a pre mainnet version. - // So we start the enum from V2 - V2(IotaGasStatusV2), + V1(IotaGasStatusV1), } impl IotaGasStatus { @@ -88,7 +86,7 @@ pub mod checked { .into()); } - Ok(Self::V2(IotaGasStatusV2::new_with_budget( + Ok(Self::V1(IotaGasStatusV1::new_with_budget( gas_budget, gas_price, reference_gas_price, @@ -97,7 +95,7 @@ pub mod checked { } pub fn new_unmetered() -> Self { - Self::V2(IotaGasStatusV2::new_unmetered()) + Self::V1(IotaGasStatusV1::new_unmetered()) } // This is the only public API on IotaGasStatus, all other gas related @@ -108,7 +106,7 @@ pub mod checked { gas_budget: u64, ) -> UserInputResult { match self { - Self::V2(status) => status.check_gas_balance(gas_objs, gas_budget), + Self::V1(status) => status.check_gas_balance(gas_objs, gas_budget), } } } diff --git a/crates/iota-types/src/gas_model/gas_v2.rs b/crates/iota-types/src/gas_model/gas_v1.rs similarity index 100% rename from crates/iota-types/src/gas_model/gas_v2.rs rename to crates/iota-types/src/gas_model/gas_v1.rs diff --git a/crates/iota-types/src/gas_model/mod.rs b/crates/iota-types/src/gas_model/mod.rs index 8e61cdcbc3a..22abf53106c 100644 --- a/crates/iota-types/src/gas_model/mod.rs +++ b/crates/iota-types/src/gas_model/mod.rs @@ -3,6 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 pub mod gas_predicates; -pub mod gas_v2; +pub mod gas_v1; pub mod tables; pub mod units_types; diff --git a/crates/iota-types/src/messages_checkpoint.rs b/crates/iota-types/src/messages_checkpoint.rs index 69c61c53d7b..4dad931676c 100644 --- a/crates/iota-types/src/messages_checkpoint.rs +++ b/crates/iota-types/src/messages_checkpoint.rs @@ -48,17 +48,6 @@ use iota_metrics::histogram::Histogram; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct CheckpointRequest { - /// if a sequence number is specified, return the checkpoint with that - /// sequence number; otherwise if None returns the latest authenticated - /// checkpoint stored. - pub sequence_number: Option, - // A flag, if true also return the contents of the - // checkpoint besides the meta-data. - pub request_content: bool, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct CheckpointRequestV2 { /// if a sequence number is specified, return the checkpoint with that /// sequence number; otherwise if None returns the latest checkpoint /// stored (authenticated or pending, depending on the value of @@ -90,13 +79,6 @@ impl CheckpointSummaryResponse { #[allow(clippy::large_enum_variant)] #[derive(Clone, Debug, Serialize, Deserialize)] pub struct CheckpointResponse { - pub checkpoint: Option, - pub contents: Option, -} - -#[allow(clippy::large_enum_variant)] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct CheckpointResponseV2 { pub checkpoint: Option, pub contents: Option, } diff --git a/crates/iota-types/src/quorum_driver_types.rs b/crates/iota-types/src/quorum_driver_types.rs index 8a8a0e15c15..2af88f912bf 100644 --- a/crates/iota-types/src/quorum_driver_types.rs +++ b/crates/iota-types/src/quorum_driver_types.rs @@ -103,17 +103,6 @@ pub enum EffectsFinalityInfo { /// is confirmed to be executed on this node before the response returns. pub type IsTransactionExecutedLocally = bool; -#[derive(Serialize, Deserialize, Clone, Debug)] -pub enum ExecuteTransactionResponse { - EffectsCert( - Box<( - FinalizedEffects, - TransactionEvents, - IsTransactionExecutedLocally, - )>, - ), -} - #[derive(Clone, Debug)] pub struct QuorumDriverRequest { pub transaction: VerifiedTransaction, @@ -131,22 +120,6 @@ pub struct QuorumDriverResponse { pub auxiliary_data: Option>, } -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct ExecuteTransactionRequest { - pub transaction: Transaction, - pub request_type: ExecuteTransactionRequestType, -} - -impl ExecuteTransactionRequest { - pub fn transaction_type(&self) -> TransactionType { - if self.transaction.contains_shared_object() { - TransactionType::SharedObject - } else { - TransactionType::SingleWriter - } - } -} - #[derive(Serialize, Deserialize, Clone, Debug)] pub struct ExecuteTransactionRequestV1 { pub transaction: Transaction, diff --git a/iota-execution/latest/iota-adapter/src/execution_engine.rs b/iota-execution/latest/iota-adapter/src/execution_engine.rs index e40a42debb1..26353e36d0a 100644 --- a/iota-execution/latest/iota-adapter/src/execution_engine.rs +++ b/iota-execution/latest/iota-adapter/src/execution_engine.rs @@ -38,7 +38,7 @@ mod checked { digests::{ChainIdentifier, get_mainnet_chain_identifier, get_testnet_chain_identifier}, effects::TransactionEffects, error::{ExecutionError, ExecutionErrorKind}, - execution::{ExecutionResults, ExecutionResultsV2, is_certificate_denied}, + execution::{ExecutionResults, ExecutionResultsV1, is_certificate_denied}, execution_config_utils::to_binary_config, execution_status::{CongestedObjects, ExecutionStatus}, gas::{GasCostSummary, IotaGasStatus}, @@ -624,8 +624,8 @@ mod checked { } } - temporary_store.record_execution_results(ExecutionResults::V2( - ExecutionResultsV2 { + temporary_store.record_execution_results(ExecutionResults::V1( + ExecutionResultsV1 { user_events: events, ..Default::default() }, diff --git a/iota-execution/latest/iota-adapter/src/programmable_transactions/context.rs b/iota-execution/latest/iota-adapter/src/programmable_transactions/context.rs index d8048eefd9e..3881633441a 100644 --- a/iota-execution/latest/iota-adapter/src/programmable_transactions/context.rs +++ b/iota-execution/latest/iota-adapter/src/programmable_transactions/context.rs @@ -22,7 +22,7 @@ mod checked { coin::Coin, error::{ExecutionError, ExecutionErrorKind, command_argument_error}, event::Event, - execution::{ExecutionResults, ExecutionResultsV2}, + execution::{ExecutionResults, ExecutionResultsV1}, execution_status::CommandArgumentError, metrics::LimitsMetrics, move_package::MovePackage, @@ -841,7 +841,7 @@ mod checked { }) .collect(); - Ok(ExecutionResults::V2(ExecutionResultsV2 { + Ok(ExecutionResults::V1(ExecutionResultsV1 { written_objects, modified_objects: loaded_runtime_objects .into_iter() diff --git a/iota-execution/latest/iota-adapter/src/temporary_store.rs b/iota-execution/latest/iota-adapter/src/temporary_store.rs index 8f2f6b1da22..1f35ae0fcf2 100644 --- a/iota-execution/latest/iota-adapter/src/temporary_store.rs +++ b/iota-execution/latest/iota-adapter/src/temporary_store.rs @@ -16,7 +16,7 @@ use iota_types::{ effects::{EffectsObjectChange, TransactionEffects, TransactionEvents}, error::{ExecutionError, IotaError, IotaResult}, execution::{ - DynamicallyLoadedObjectMetadata, ExecutionResults, ExecutionResultsV2, SharedInput, + DynamicallyLoadedObjectMetadata, ExecutionResults, ExecutionResultsV1, SharedInput, }, execution_config_utils::to_binary_config, execution_status::ExecutionStatus, @@ -53,7 +53,7 @@ pub struct TemporaryStore<'backing> { /// this store. lamport_timestamp: SequenceNumber, mutable_input_refs: BTreeMap, // Inputs that are mutable - execution_results: ExecutionResultsV2, + execution_results: ExecutionResultsV1, /// Objects that were loaded during execution (dynamic fields + received /// objects). loaded_runtime_objects: BTreeMap, @@ -117,7 +117,7 @@ impl<'backing> TemporaryStore<'backing> { input_objects: objects, lamport_timestamp, mutable_input_refs, - execution_results: ExecutionResultsV2::default(), + execution_results: ExecutionResultsV1::default(), protocol_config, loaded_runtime_objects: BTreeMap::new(), wrapped_object_containers: BTreeMap::new(), @@ -257,7 +257,7 @@ impl<'backing> TemporaryStore<'backing> { let loaded_per_epoch_config_objects = self.loaded_per_epoch_config_objects.read().clone(); let inner = self.into_inner(); - let effects = TransactionEffects::new_from_execution_v2( + let effects = TransactionEffects::new_from_execution_v1( status, epoch, gas_cost_summary, @@ -444,7 +444,7 @@ impl<'backing> TemporaryStore<'backing> { } pub fn estimate_effects_size_upperbound(&self) -> usize { - TransactionEffects::estimate_effects_size_upperbound_v2( + TransactionEffects::estimate_effects_size_upperbound_v1( self.execution_results.written_objects.len(), self.execution_results.modified_objects.len(), self.input_objects.len(), @@ -1025,12 +1025,10 @@ impl<'backing> Storage for TemporaryStore<'backing> { TemporaryStore::read_object(self, id) } - /// Take execution results v2, and translate it back to be compatible with - /// effects v1. + /// Take execution results v1. fn record_execution_results(&mut self, results: ExecutionResults) { - let ExecutionResults::V2(results) = results else { - panic!("ExecutionResults::V2 expected in iota-execution v1 and above"); - }; + let ExecutionResults::V1(results) = results; + // It's important to merge instead of override results because it's // possible to execute PT more than once during tx execution. self.execution_results.merge_results(results); diff --git a/iota-execution/latest/iota-move-natives/src/object_runtime/mod.rs b/iota-execution/latest/iota-move-natives/src/object_runtime/mod.rs index 88466de596f..9244a158540 100644 --- a/iota-execution/latest/iota-move-natives/src/object_runtime/mod.rs +++ b/iota-execution/latest/iota-move-natives/src/object_runtime/mod.rs @@ -693,15 +693,15 @@ pub fn get_all_uids( bcs_bytes: &[u8], ) -> Result, /* invariant violation */ String> { let mut ids = BTreeSet::new(); - struct UIDTraversalV2<'i>(&'i mut BTreeSet); - struct UIDCollectorV2<'i>(&'i mut BTreeSet); + struct UIDTraversalV1<'i>(&'i mut BTreeSet); + struct UIDCollectorV1<'i>(&'i mut BTreeSet); - impl<'i> AV::Traversal for UIDTraversalV2<'i> { + impl<'i> AV::Traversal for UIDTraversalV1<'i> { type Error = AV::Error; fn traverse_struct(&mut self, driver: &mut AV::StructDriver) -> Result<(), Self::Error> { if driver.struct_layout().type_ == UID::type_() { - while driver.next_field(&mut UIDCollectorV2(self.0))?.is_some() {} + while driver.next_field(&mut UIDCollectorV1(self.0))?.is_some() {} } else { while driver.next_field(self)?.is_some() {} } @@ -709,7 +709,7 @@ pub fn get_all_uids( } } - impl<'i> AV::Traversal for UIDCollectorV2<'i> { + impl<'i> AV::Traversal for UIDCollectorV1<'i> { type Error = AV::Error; fn traverse_address(&mut self, value: AccountAddress) -> Result<(), Self::Error> { self.0.insert(value.into()); @@ -720,7 +720,7 @@ pub fn get_all_uids( MoveValue::visit_deserialize( bcs_bytes, fully_annotated_layout, - &mut UIDTraversalV2(&mut ids), + &mut UIDTraversalV1(&mut ids), ) .map_err(|e| format!("Failed to deserialize. {e:?}"))?; Ok(ids) diff --git a/iota-execution/v0/iota-adapter/src/execution_engine.rs b/iota-execution/v0/iota-adapter/src/execution_engine.rs index bfbc94ffc70..c4361c81a06 100644 --- a/iota-execution/v0/iota-adapter/src/execution_engine.rs +++ b/iota-execution/v0/iota-adapter/src/execution_engine.rs @@ -38,7 +38,7 @@ mod checked { digests::{ChainIdentifier, get_mainnet_chain_identifier, get_testnet_chain_identifier}, effects::TransactionEffects, error::{ExecutionError, ExecutionErrorKind}, - execution::{ExecutionResults, ExecutionResultsV2, is_certificate_denied}, + execution::{ExecutionResults, ExecutionResultsV1, is_certificate_denied}, execution_config_utils::to_binary_config, execution_status::{CongestedObjects, ExecutionStatus}, gas::{GasCostSummary, IotaGasStatus}, @@ -577,8 +577,8 @@ mod checked { } } - temporary_store.record_execution_results(ExecutionResults::V2( - ExecutionResultsV2 { + temporary_store.record_execution_results(ExecutionResults::V1( + ExecutionResultsV1 { user_events: events, ..Default::default() }, diff --git a/iota-execution/v0/iota-adapter/src/programmable_transactions/context.rs b/iota-execution/v0/iota-adapter/src/programmable_transactions/context.rs index 542e93ab75b..f5c630c28ec 100644 --- a/iota-execution/v0/iota-adapter/src/programmable_transactions/context.rs +++ b/iota-execution/v0/iota-adapter/src/programmable_transactions/context.rs @@ -22,7 +22,7 @@ mod checked { coin::Coin, error::{ExecutionError, ExecutionErrorKind, command_argument_error}, event::Event, - execution::{ExecutionResults, ExecutionResultsV2}, + execution::{ExecutionResults, ExecutionResultsV1}, execution_status::CommandArgumentError, metrics::LimitsMetrics, move_package::MovePackage, @@ -834,7 +834,7 @@ mod checked { }) .collect(); - Ok(ExecutionResults::V2(ExecutionResultsV2 { + Ok(ExecutionResults::V1(ExecutionResultsV1 { written_objects, modified_objects: loaded_runtime_objects .into_iter() diff --git a/iota-execution/v0/iota-adapter/src/temporary_store.rs b/iota-execution/v0/iota-adapter/src/temporary_store.rs index 8f2f6b1da22..1f35ae0fcf2 100644 --- a/iota-execution/v0/iota-adapter/src/temporary_store.rs +++ b/iota-execution/v0/iota-adapter/src/temporary_store.rs @@ -16,7 +16,7 @@ use iota_types::{ effects::{EffectsObjectChange, TransactionEffects, TransactionEvents}, error::{ExecutionError, IotaError, IotaResult}, execution::{ - DynamicallyLoadedObjectMetadata, ExecutionResults, ExecutionResultsV2, SharedInput, + DynamicallyLoadedObjectMetadata, ExecutionResults, ExecutionResultsV1, SharedInput, }, execution_config_utils::to_binary_config, execution_status::ExecutionStatus, @@ -53,7 +53,7 @@ pub struct TemporaryStore<'backing> { /// this store. lamport_timestamp: SequenceNumber, mutable_input_refs: BTreeMap, // Inputs that are mutable - execution_results: ExecutionResultsV2, + execution_results: ExecutionResultsV1, /// Objects that were loaded during execution (dynamic fields + received /// objects). loaded_runtime_objects: BTreeMap, @@ -117,7 +117,7 @@ impl<'backing> TemporaryStore<'backing> { input_objects: objects, lamport_timestamp, mutable_input_refs, - execution_results: ExecutionResultsV2::default(), + execution_results: ExecutionResultsV1::default(), protocol_config, loaded_runtime_objects: BTreeMap::new(), wrapped_object_containers: BTreeMap::new(), @@ -257,7 +257,7 @@ impl<'backing> TemporaryStore<'backing> { let loaded_per_epoch_config_objects = self.loaded_per_epoch_config_objects.read().clone(); let inner = self.into_inner(); - let effects = TransactionEffects::new_from_execution_v2( + let effects = TransactionEffects::new_from_execution_v1( status, epoch, gas_cost_summary, @@ -444,7 +444,7 @@ impl<'backing> TemporaryStore<'backing> { } pub fn estimate_effects_size_upperbound(&self) -> usize { - TransactionEffects::estimate_effects_size_upperbound_v2( + TransactionEffects::estimate_effects_size_upperbound_v1( self.execution_results.written_objects.len(), self.execution_results.modified_objects.len(), self.input_objects.len(), @@ -1025,12 +1025,10 @@ impl<'backing> Storage for TemporaryStore<'backing> { TemporaryStore::read_object(self, id) } - /// Take execution results v2, and translate it back to be compatible with - /// effects v1. + /// Take execution results v1. fn record_execution_results(&mut self, results: ExecutionResults) { - let ExecutionResults::V2(results) = results else { - panic!("ExecutionResults::V2 expected in iota-execution v1 and above"); - }; + let ExecutionResults::V1(results) = results; + // It's important to merge instead of override results because it's // possible to execute PT more than once during tx execution. self.execution_results.merge_results(results); diff --git a/iota-execution/v0/iota-move-natives/src/object_runtime/mod.rs b/iota-execution/v0/iota-move-natives/src/object_runtime/mod.rs index 88466de596f..9244a158540 100644 --- a/iota-execution/v0/iota-move-natives/src/object_runtime/mod.rs +++ b/iota-execution/v0/iota-move-natives/src/object_runtime/mod.rs @@ -693,15 +693,15 @@ pub fn get_all_uids( bcs_bytes: &[u8], ) -> Result, /* invariant violation */ String> { let mut ids = BTreeSet::new(); - struct UIDTraversalV2<'i>(&'i mut BTreeSet); - struct UIDCollectorV2<'i>(&'i mut BTreeSet); + struct UIDTraversalV1<'i>(&'i mut BTreeSet); + struct UIDCollectorV1<'i>(&'i mut BTreeSet); - impl<'i> AV::Traversal for UIDTraversalV2<'i> { + impl<'i> AV::Traversal for UIDTraversalV1<'i> { type Error = AV::Error; fn traverse_struct(&mut self, driver: &mut AV::StructDriver) -> Result<(), Self::Error> { if driver.struct_layout().type_ == UID::type_() { - while driver.next_field(&mut UIDCollectorV2(self.0))?.is_some() {} + while driver.next_field(&mut UIDCollectorV1(self.0))?.is_some() {} } else { while driver.next_field(self)?.is_some() {} } @@ -709,7 +709,7 @@ pub fn get_all_uids( } } - impl<'i> AV::Traversal for UIDCollectorV2<'i> { + impl<'i> AV::Traversal for UIDCollectorV1<'i> { type Error = AV::Error; fn traverse_address(&mut self, value: AccountAddress) -> Result<(), Self::Error> { self.0.insert(value.into()); @@ -720,7 +720,7 @@ pub fn get_all_uids( MoveValue::visit_deserialize( bcs_bytes, fully_annotated_layout, - &mut UIDTraversalV2(&mut ids), + &mut UIDTraversalV1(&mut ids), ) .map_err(|e| format!("Failed to deserialize. {e:?}"))?; Ok(ids)