casper_storage/global_state/state/
mod.rs

1//! Global state.
2
3/// Lmdb implementation of global state.
4pub mod lmdb;
5
6/// Lmdb implementation of global state with cache.
7pub mod scratch;
8
9use num_rational::Ratio;
10use parking_lot::RwLock;
11use std::{
12    cell::RefCell,
13    collections::{BTreeMap, BTreeSet},
14    convert::TryFrom,
15    rc::Rc,
16    sync::Arc,
17};
18
19use tracing::{debug, error, info, warn};
20
21use casper_types::{
22    account::AccountHash,
23    bytesrepr::{self, ToBytes},
24    contracts::NamedKeys,
25    execution::{Effects, TransformError, TransformInstruction, TransformKindV2, TransformV2},
26    global_state::TrieMerkleProof,
27    system::{
28        self,
29        auction::{
30            SeigniorageRecipientsSnapshot, ERA_END_TIMESTAMP_MILLIS_KEY, ERA_ID_KEY,
31            SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY, SEIGNIORAGE_RECIPIENTS_SNAPSHOT_VERSION_KEY,
32        },
33        mint::{
34            BalanceHoldAddr, BalanceHoldAddrTag, ARG_AMOUNT, ROUND_SEIGNIORAGE_RATE_KEY,
35            TOTAL_SUPPLY_KEY,
36        },
37        AUCTION, HANDLE_PAYMENT, MINT,
38    },
39    Account, AddressableEntity, BlockGlobalAddr, CLValue, Digest, EntityAddr, EntityEntryPoint,
40    EntryPointAddr, EntryPointValue, HoldsEpoch, Key, KeyTag, Phase, PublicKey, RuntimeArgs,
41    StoredValue, SystemHashRegistry, U512,
42};
43
44#[cfg(test)]
45pub use self::lmdb::make_temporary_global_state;
46
47use super::trie_store::{operations::batch_write, TrieStoreCacheError};
48use crate::{
49    data_access_layer::{
50        auction::{AuctionMethodRet, BiddingRequest, BiddingResult},
51        balance::BalanceHandling,
52        era_validators::EraValidatorsResult,
53        handle_fee::{HandleFeeMode, HandleFeeRequest, HandleFeeResult},
54        mint::{
55            BurnRequest, BurnRequestArgs, BurnResult, TransferRequest, TransferRequestArgs,
56            TransferResult,
57        },
58        prefixed_values::{PrefixedValuesRequest, PrefixedValuesResult},
59        tagged_values::{TaggedValuesRequest, TaggedValuesResult},
60        AddressableEntityRequest, AddressableEntityResult, AuctionMethod, BalanceHoldError,
61        BalanceHoldKind, BalanceHoldMode, BalanceHoldRequest, BalanceHoldResult, BalanceIdentifier,
62        BalanceIdentifierPurseRequest, BalanceIdentifierPurseResult, BalanceRequest, BalanceResult,
63        BidsRequest, BidsResult, BlockGlobalKind, BlockGlobalRequest, BlockGlobalResult,
64        BlockRewardsError, BlockRewardsRequest, BlockRewardsResult, ContractRequest,
65        ContractResult, EntryPointExistsRequest, EntryPointExistsResult, EntryPointRequest,
66        EntryPointResult, EraValidatorsRequest, ExecutionResultsChecksumRequest,
67        ExecutionResultsChecksumResult, FeeError, FeeRequest, FeeResult, FlushRequest, FlushResult,
68        GenesisRequest, GenesisResult, HandleRefundMode, HandleRefundRequest, HandleRefundResult,
69        InsufficientBalanceHandling, MessageTopicsRequest, MessageTopicsResult, ProofHandling,
70        ProofsResult, ProtocolUpgradeRequest, ProtocolUpgradeResult, PruneRequest, PruneResult,
71        PutTrieRequest, PutTrieResult, QueryRequest, QueryResult, RoundSeigniorageRateRequest,
72        RoundSeigniorageRateResult, SeigniorageRecipientsRequest, SeigniorageRecipientsResult,
73        StepError, StepRequest, StepResult, SystemEntityRegistryPayload,
74        SystemEntityRegistryRequest, SystemEntityRegistryResult, SystemEntityRegistrySelector,
75        TotalSupplyRequest, TotalSupplyResult, TrieRequest, TrieResult,
76        EXECUTION_RESULTS_CHECKSUM_NAME,
77    },
78    global_state::{
79        error::Error as GlobalStateError,
80        state::scratch::ScratchGlobalState,
81        transaction_source::{Transaction, TransactionSource},
82        trie::Trie,
83        trie_store::{
84            operations::{prune, read, write, ReadResult, TriePruneResult, WriteResult},
85            TrieStore,
86        },
87    },
88    system::{
89        auction::{self, Auction},
90        burn::{BurnError, BurnRuntimeArgsBuilder},
91        genesis::{GenesisError, GenesisInstaller},
92        handle_payment::HandlePayment,
93        mint::Mint,
94        protocol_upgrade::{ProtocolUpgradeError, ProtocolUpgrader},
95        runtime_native::{Id, RuntimeNative},
96        transfer::{TransferArgs, TransferError, TransferRuntimeArgsBuilder, TransferTargetMode},
97    },
98    tracking_copy::{TrackingCopy, TrackingCopyEntityExt, TrackingCopyError, TrackingCopyExt},
99    AddressGenerator,
100};
101
102/// A trait expressing the reading of state. This trait is used to abstract the underlying store.
103pub trait StateReader<K = Key, V = StoredValue>: Sized + Send + Sync {
104    /// An error which occurs when reading state
105    type Error;
106
107    /// Returns the state value from the corresponding key
108    fn read(&self, key: &K) -> Result<Option<V>, Self::Error>;
109
110    /// Returns the merkle proof of the state value from the corresponding key
111    fn read_with_proof(&self, key: &K) -> Result<Option<TrieMerkleProof<K, V>>, Self::Error>;
112
113    /// Returns the keys in the trie matching `prefix`.
114    fn keys_with_prefix(&self, prefix: &[u8]) -> Result<Vec<K>, Self::Error>;
115}
116
117/// An error emitted by the execution engine on commit
118#[derive(Clone, Debug, thiserror::Error, Eq, PartialEq)]
119pub enum CommitError {
120    /// Root not found.
121    #[error("Root not found: {0:?}")]
122    RootNotFound(Digest),
123    /// Root not found while attempting to read.
124    #[error("Root not found while attempting to read: {0:?}")]
125    ReadRootNotFound(Digest),
126    /// Root not found while attempting to write.
127    #[error("Root not found while writing: {0:?}")]
128    WriteRootNotFound(Digest),
129    /// Key not found.
130    #[error("Key not found: {0}")]
131    KeyNotFound(Key),
132    /// Transform error.
133    #[error(transparent)]
134    TransformError(TransformError),
135    /// Trie not found while attempting to validate cache write.
136    #[error("Trie not found in cache {0}")]
137    TrieNotFoundInCache(Digest),
138}
139
140/// Scratch provider.
141pub trait ScratchProvider: CommitProvider {
142    /// Get scratch state to db.
143    fn get_scratch_global_state(&self) -> ScratchGlobalState;
144    /// Write scratch state to db.
145    fn write_scratch_to_db(
146        &self,
147        state_root_hash: Digest,
148        scratch_global_state: ScratchGlobalState,
149    ) -> Result<Digest, GlobalStateError>;
150    /// Prune items for imputed keys.
151    fn prune_keys(&self, state_root_hash: Digest, keys: &[Key]) -> TriePruneResult;
152}
153
154/// Provides `commit` method.
155pub trait CommitProvider: StateProvider {
156    /// Applies changes and returns a new post state hash.
157    /// block_hash is used for computing a deterministic and unique keys.
158    fn commit_effects(
159        &self,
160        state_hash: Digest,
161        effects: Effects,
162    ) -> Result<Digest, GlobalStateError>;
163
164    /// Commit values to global state.
165    fn commit_values(
166        &self,
167        state_hash: Digest,
168        values_to_write: Vec<(Key, StoredValue)>,
169        keys_to_prune: BTreeSet<Key>,
170    ) -> Result<Digest, GlobalStateError>;
171
172    /// Runs and commits the genesis process, once per network.
173    fn genesis(&self, request: GenesisRequest) -> GenesisResult {
174        let initial_root = self.empty_root();
175        let tc = match self.tracking_copy(initial_root) {
176            Ok(Some(tc)) => Rc::new(RefCell::new(tc)),
177            Ok(None) => return GenesisResult::Fatal("state uninitialized".to_string()),
178            Err(err) => {
179                return GenesisResult::Failure(GenesisError::TrackingCopy(
180                    TrackingCopyError::Storage(err),
181                ));
182            }
183        };
184        let chainspec_hash = request.chainspec_hash();
185        let protocol_version = request.protocol_version();
186        let config = request.config();
187
188        let mut genesis_installer: GenesisInstaller<Self> =
189            GenesisInstaller::new(chainspec_hash, protocol_version, config.clone(), tc);
190
191        let chainspec_registry = request.chainspec_registry();
192        if let Err(gen_err) = genesis_installer.install(chainspec_registry.clone()) {
193            return GenesisResult::Failure(*gen_err);
194        }
195
196        let effects = genesis_installer.finalize();
197        match self.commit_effects(initial_root, effects.clone()) {
198            Ok(post_state_hash) => GenesisResult::Success {
199                post_state_hash,
200                effects,
201            },
202            Err(err) => {
203                GenesisResult::Failure(GenesisError::TrackingCopy(TrackingCopyError::Storage(err)))
204            }
205        }
206    }
207
208    /// Runs and commits the protocol upgrade process.
209    fn protocol_upgrade(&self, request: ProtocolUpgradeRequest) -> ProtocolUpgradeResult {
210        let pre_state_hash = request.pre_state_hash();
211        let tc = match self.tracking_copy(pre_state_hash) {
212            Ok(Some(tc)) => tc,
213            Ok(None) => return ProtocolUpgradeResult::RootNotFound,
214            Err(err) => {
215                return ProtocolUpgradeResult::Failure(ProtocolUpgradeError::TrackingCopy(
216                    TrackingCopyError::Storage(err),
217                ));
218            }
219        };
220
221        let protocol_upgrader: ProtocolUpgrader<Self> =
222            ProtocolUpgrader::new(request.config().clone(), pre_state_hash, tc);
223
224        let post_upgrade_tc = match protocol_upgrader.upgrade(pre_state_hash) {
225            Err(e) => return e.into(),
226            Ok(tc) => tc,
227        };
228
229        let (writes, prunes, effects) = post_upgrade_tc.destructure();
230
231        // commit
232        match self.commit_values(pre_state_hash, writes, prunes) {
233            Ok(post_state_hash) => ProtocolUpgradeResult::Success {
234                post_state_hash,
235                effects,
236            },
237            Err(err) => ProtocolUpgradeResult::Failure(ProtocolUpgradeError::TrackingCopy(
238                TrackingCopyError::Storage(err),
239            )),
240        }
241    }
242
243    /// Safely prune specified keys from global state, using a tracking copy.
244    fn prune(&self, request: PruneRequest) -> PruneResult {
245        let pre_state_hash = request.state_hash();
246        let tc = match self.tracking_copy(pre_state_hash) {
247            Ok(Some(tc)) => Rc::new(RefCell::new(tc)),
248            Ok(None) => return PruneResult::RootNotFound,
249            Err(err) => return PruneResult::Failure(TrackingCopyError::Storage(err)),
250        };
251
252        let keys_to_delete = request.keys_to_prune();
253        if keys_to_delete.is_empty() {
254            // effectively a noop
255            return PruneResult::Success {
256                post_state_hash: pre_state_hash,
257                effects: Effects::default(),
258            };
259        }
260
261        for key in keys_to_delete {
262            tc.borrow_mut().prune(*key)
263        }
264
265        let effects = tc.borrow().effects();
266
267        match self.commit_effects(pre_state_hash, effects.clone()) {
268            Ok(post_state_hash) => PruneResult::Success {
269                post_state_hash,
270                effects,
271            },
272            Err(tce) => PruneResult::Failure(tce.into()),
273        }
274    }
275
276    /// Step auction state at era end.
277    fn step(&self, request: StepRequest) -> StepResult {
278        let state_hash = request.state_hash();
279        let tc = match self.tracking_copy(state_hash) {
280            Ok(Some(tc)) => Rc::new(RefCell::new(tc)),
281            Ok(None) => return StepResult::RootNotFound,
282            Err(err) => {
283                return StepResult::Failure(StepError::TrackingCopy(TrackingCopyError::Storage(
284                    err,
285                )));
286            }
287        };
288        let protocol_version = request.protocol_version();
289
290        let seed = {
291            // seeds address generator w/ era_end_timestamp_millis
292            let mut bytes = match request.era_end_timestamp_millis().into_bytes() {
293                Ok(bytes) => bytes,
294                Err(bre) => {
295                    return StepResult::Failure(StepError::TrackingCopy(
296                        TrackingCopyError::BytesRepr(bre),
297                    ));
298                }
299            };
300            match &mut protocol_version.into_bytes() {
301                Ok(next) => bytes.append(next),
302                Err(bre) => {
303                    return StepResult::Failure(StepError::TrackingCopy(
304                        TrackingCopyError::BytesRepr(*bre),
305                    ));
306                }
307            };
308            match &mut request.next_era_id().into_bytes() {
309                Ok(next) => bytes.append(next),
310                Err(bre) => {
311                    return StepResult::Failure(StepError::TrackingCopy(
312                        TrackingCopyError::BytesRepr(*bre),
313                    ));
314                }
315            };
316
317            Id::Seed(bytes)
318        };
319
320        let config = request.config();
321        // this runtime uses the system's context
322        let phase = Phase::Session;
323        let address_generator = AddressGenerator::new(&seed.seed(), phase);
324        let mut runtime = match RuntimeNative::new_system_runtime(
325            config.clone(),
326            protocol_version,
327            seed,
328            Arc::new(RwLock::new(address_generator)),
329            Rc::clone(&tc),
330            phase,
331        ) {
332            Ok(rt) => rt,
333            Err(tce) => return StepResult::Failure(StepError::TrackingCopy(tce)),
334        };
335
336        let slashed_validators: Vec<PublicKey> = request.slashed_validators();
337        if !slashed_validators.is_empty() {
338            if let Err(err) = runtime.slash(slashed_validators) {
339                error!("{}", err);
340                return StepResult::Failure(StepError::SlashingError);
341            }
342        }
343
344        let era_end_timestamp_millis = request.era_end_timestamp_millis();
345        let evicted_validators = request
346            .evict_items()
347            .iter()
348            .map(|item| item.validator_id.clone())
349            .collect::<Vec<PublicKey>>();
350        let max_delegators_per_validator = config.max_delegators_per_validator();
351        let include_credits = config.include_credits();
352        let credit_cap = config.credit_cap();
353        let minimum_bid_amount = config.minimum_bid_amount();
354
355        if let Err(err) = runtime.run_auction(
356            era_end_timestamp_millis,
357            evicted_validators,
358            max_delegators_per_validator,
359            include_credits,
360            credit_cap,
361            minimum_bid_amount,
362        ) {
363            error!("{}", err);
364            return StepResult::Failure(StepError::Auction);
365        }
366
367        let effects = tc.borrow().effects();
368
369        match self.commit_effects(state_hash, effects.clone()) {
370            Ok(post_state_hash) => StepResult::Success {
371                post_state_hash,
372                effects,
373            },
374            Err(gse) => StepResult::Failure(gse.into()),
375        }
376    }
377
378    /// Distribute block rewards.
379    fn distribute_block_rewards(&self, request: BlockRewardsRequest) -> BlockRewardsResult {
380        let state_hash = request.state_hash();
381        let rewards = request.rewards();
382        if rewards.is_empty() {
383            info!("rewards are empty");
384            // if there are no rewards to distribute, this is effectively a noop
385            return BlockRewardsResult::Success {
386                post_state_hash: state_hash,
387                effects: Effects::new(),
388            };
389        }
390
391        let tc = match self.tracking_copy(state_hash) {
392            Ok(Some(tc)) => Rc::new(RefCell::new(tc)),
393            Ok(None) => return BlockRewardsResult::RootNotFound,
394            Err(err) => {
395                return BlockRewardsResult::Failure(BlockRewardsError::TrackingCopy(
396                    TrackingCopyError::Storage(err),
397                ));
398            }
399        };
400
401        let config = request.config();
402        let protocol_version = request.protocol_version();
403        let seed = {
404            let mut bytes = match request.block_time().into_bytes() {
405                Ok(bytes) => bytes,
406                Err(bre) => {
407                    return BlockRewardsResult::Failure(BlockRewardsError::TrackingCopy(
408                        TrackingCopyError::BytesRepr(bre),
409                    ));
410                }
411            };
412            match &mut protocol_version.into_bytes() {
413                Ok(next) => bytes.append(next),
414                Err(bre) => {
415                    return BlockRewardsResult::Failure(BlockRewardsError::TrackingCopy(
416                        TrackingCopyError::BytesRepr(*bre),
417                    ));
418                }
419            };
420
421            Id::Seed(bytes)
422        };
423
424        // this runtime uses the system's context
425        let phase = Phase::Session;
426        let address_generator = AddressGenerator::new(&seed.seed(), phase);
427
428        let mut runtime = match RuntimeNative::new_system_runtime(
429            config.clone(),
430            protocol_version,
431            seed,
432            Arc::new(RwLock::new(address_generator)),
433            Rc::clone(&tc),
434            phase,
435        ) {
436            Ok(rt) => rt,
437            Err(tce) => {
438                return BlockRewardsResult::Failure(BlockRewardsError::TrackingCopy(tce));
439            }
440        };
441
442        if let Err(auction_error) = runtime.distribute(rewards.clone()) {
443            error!(
444                "distribute block rewards failed due to auction error {:?}",
445                auction_error
446            );
447            return BlockRewardsResult::Failure(BlockRewardsError::Auction(auction_error));
448        } else {
449            debug!("rewards distribution complete");
450        }
451
452        let effects = tc.borrow().effects();
453
454        match self.commit_effects(state_hash, effects.clone()) {
455            Ok(post_state_hash) => {
456                debug!("reward distribution committed");
457                BlockRewardsResult::Success {
458                    post_state_hash,
459                    effects,
460                }
461            }
462            Err(gse) => BlockRewardsResult::Failure(BlockRewardsError::TrackingCopy(
463                TrackingCopyError::Storage(gse),
464            )),
465        }
466    }
467
468    /// Distribute fees, if relevant to the chainspec configured behavior.
469    fn distribute_fees(&self, request: FeeRequest) -> FeeResult {
470        let state_hash = request.state_hash();
471        if !request.should_distribute_fees() {
472            // effectively noop
473            return FeeResult::Success {
474                post_state_hash: state_hash,
475                effects: Effects::new(),
476                transfers: vec![],
477            };
478        }
479
480        let tc = match self.tracking_copy(state_hash) {
481            Ok(Some(tracking_copy)) => Rc::new(RefCell::new(tracking_copy)),
482            Ok(None) => return FeeResult::RootNotFound,
483            Err(gse) => {
484                return FeeResult::Failure(FeeError::TrackingCopy(TrackingCopyError::Storage(gse)));
485            }
486        };
487
488        let config = request.config();
489        let protocol_version = request.protocol_version();
490        let seed = {
491            let mut bytes = match request.block_time().into_bytes() {
492                Ok(bytes) => bytes,
493                Err(bre) => {
494                    return FeeResult::Failure(FeeError::TrackingCopy(
495                        TrackingCopyError::BytesRepr(bre),
496                    ));
497                }
498            };
499            match &mut protocol_version.into_bytes() {
500                Ok(next) => bytes.append(next),
501                Err(bre) => {
502                    return FeeResult::Failure(FeeError::TrackingCopy(
503                        TrackingCopyError::BytesRepr(*bre),
504                    ));
505                }
506            };
507
508            Id::Seed(bytes)
509        };
510
511        // this runtime uses the system's context
512        let phase = Phase::System;
513        let address_generator = AddressGenerator::new(&seed.seed(), phase);
514        let mut runtime = match RuntimeNative::new_system_runtime(
515            config.clone(),
516            protocol_version,
517            seed,
518            Arc::new(RwLock::new(address_generator)),
519            Rc::clone(&tc),
520            phase,
521        ) {
522            Ok(rt) => rt,
523            Err(tce) => {
524                return FeeResult::Failure(FeeError::TrackingCopy(tce));
525            }
526        };
527
528        let source = BalanceIdentifier::Accumulate;
529        let source_purse = match source.purse_uref(&mut tc.borrow_mut(), protocol_version) {
530            Ok(value) => value,
531            Err(tce) => return FeeResult::Failure(FeeError::TrackingCopy(tce)),
532        };
533        // amount = None will distribute the full current balance of the accumulation purse
534        let result = runtime.distribute_accumulated_fees(source_purse, None);
535
536        match result {
537            Ok(_) => {
538                let effects = tc.borrow_mut().effects();
539                let transfers = runtime.into_transfers();
540                let post_state_hash = match self.commit_effects(state_hash, effects.clone()) {
541                    Ok(post_state_hash) => post_state_hash,
542                    Err(gse) => {
543                        return FeeResult::Failure(FeeError::TrackingCopy(
544                            TrackingCopyError::Storage(gse),
545                        ));
546                    }
547                };
548                FeeResult::Success {
549                    effects,
550                    transfers,
551                    post_state_hash,
552                }
553            }
554            Err(hpe) => FeeResult::Failure(FeeError::TrackingCopy(
555                TrackingCopyError::SystemContract(system::Error::HandlePayment(hpe)),
556            )),
557        }
558    }
559
560    /// Gets block global data.
561    fn block_global(&self, request: BlockGlobalRequest) -> BlockGlobalResult {
562        let state_hash = request.state_hash();
563        let tc = match self.tracking_copy(state_hash) {
564            Ok(Some(tracking_copy)) => Rc::new(RefCell::new(tracking_copy)),
565            Ok(None) => return BlockGlobalResult::RootNotFound,
566            Err(gse) => return BlockGlobalResult::Failure(TrackingCopyError::Storage(gse)),
567        };
568
569        // match request
570        match request.block_global_kind() {
571            BlockGlobalKind::BlockTime(block_time) => {
572                let cl_value =
573                    match CLValue::from_t(block_time.value()).map_err(TrackingCopyError::CLValue) {
574                        Ok(cl_value) => cl_value,
575                        Err(tce) => {
576                            return BlockGlobalResult::Failure(tce);
577                        }
578                    };
579                tc.borrow_mut().write(
580                    Key::BlockGlobal(BlockGlobalAddr::BlockTime),
581                    StoredValue::CLValue(cl_value),
582                );
583            }
584            BlockGlobalKind::MessageCount(count) => {
585                let cl_value = match CLValue::from_t(count).map_err(TrackingCopyError::CLValue) {
586                    Ok(cl_value) => cl_value,
587                    Err(tce) => {
588                        return BlockGlobalResult::Failure(tce);
589                    }
590                };
591                tc.borrow_mut().write(
592                    Key::BlockGlobal(BlockGlobalAddr::MessageCount),
593                    StoredValue::CLValue(cl_value),
594                );
595            }
596            BlockGlobalKind::ProtocolVersion(protocol_version) => {
597                let cl_value = match CLValue::from_t(protocol_version.destructure())
598                    .map_err(TrackingCopyError::CLValue)
599                {
600                    Ok(cl_value) => cl_value,
601                    Err(tce) => {
602                        return BlockGlobalResult::Failure(tce);
603                    }
604                };
605                tc.borrow_mut().write(
606                    Key::BlockGlobal(BlockGlobalAddr::ProtocolVersion),
607                    StoredValue::CLValue(cl_value),
608                );
609            }
610            BlockGlobalKind::AddressableEntity(addressable_entity) => {
611                let cl_value =
612                    match CLValue::from_t(addressable_entity).map_err(TrackingCopyError::CLValue) {
613                        Ok(cl_value) => cl_value,
614                        Err(tce) => {
615                            return BlockGlobalResult::Failure(tce);
616                        }
617                    };
618                tc.borrow_mut().write(
619                    Key::BlockGlobal(BlockGlobalAddr::AddressableEntity),
620                    StoredValue::CLValue(cl_value),
621                );
622            }
623        }
624
625        let effects = tc.borrow_mut().effects();
626
627        let post_state_hash = match self.commit_effects(state_hash, effects.clone()) {
628            Ok(post_state_hash) => post_state_hash,
629            Err(gse) => return BlockGlobalResult::Failure(TrackingCopyError::Storage(gse)),
630        };
631
632        BlockGlobalResult::Success {
633            post_state_hash,
634            effects: Box::new(effects),
635        }
636    }
637}
638
639/// A trait expressing operations over the trie.
640pub trait StateProvider: Send + Sync + Sized {
641    /// Associated reader type for `StateProvider`.
642    type Reader: StateReader<Key, StoredValue, Error = GlobalStateError>;
643
644    /// Flush the state provider.
645    fn flush(&self, request: FlushRequest) -> FlushResult;
646
647    /// Returns an empty root hash.
648    fn empty_root(&self) -> Digest;
649
650    /// Get a tracking copy.
651    fn tracking_copy(
652        &self,
653        state_hash: Digest,
654    ) -> Result<Option<TrackingCopy<Self::Reader>>, GlobalStateError>;
655
656    /// Checkouts a slice of initial state using root state hash.
657    fn checkout(&self, state_hash: Digest) -> Result<Option<Self::Reader>, GlobalStateError>;
658
659    /// Query state.
660    fn query(&self, request: QueryRequest) -> QueryResult {
661        match self.tracking_copy(request.state_hash()) {
662            Ok(Some(tc)) => match tc.query(request.key(), request.path()) {
663                Ok(ret) => ret.into(),
664                Err(err) => QueryResult::Failure(err),
665            },
666            Ok(None) => QueryResult::RootNotFound,
667            Err(err) => QueryResult::Failure(TrackingCopyError::Storage(err)),
668        }
669    }
670
671    /// Message topics request.
672    fn message_topics(&self, message_topics_request: MessageTopicsRequest) -> MessageTopicsResult {
673        let tc = match self.tracking_copy(message_topics_request.state_hash()) {
674            Ok(Some(tracking_copy)) => tracking_copy,
675            Ok(None) => return MessageTopicsResult::RootNotFound,
676            Err(err) => return MessageTopicsResult::Failure(err.into()),
677        };
678
679        match tc.get_message_topics(message_topics_request.entity_addr()) {
680            Ok(message_topics) => MessageTopicsResult::Success { message_topics },
681            Err(tce) => MessageTopicsResult::Failure(tce),
682        }
683    }
684
685    /// Provides the underlying addr for the imputed balance identifier.
686    fn balance_purse(
687        &self,
688        request: BalanceIdentifierPurseRequest,
689    ) -> BalanceIdentifierPurseResult {
690        let mut tc = match self.tracking_copy(request.state_hash()) {
691            Ok(Some(tracking_copy)) => tracking_copy,
692            Ok(None) => return BalanceIdentifierPurseResult::RootNotFound,
693            Err(err) => return TrackingCopyError::Storage(err).into(),
694        };
695        let balance_identifier = request.identifier();
696        let protocol_version = request.protocol_version();
697        match balance_identifier.purse_uref(&mut tc, protocol_version) {
698            Ok(uref) => BalanceIdentifierPurseResult::Success {
699                purse_addr: uref.addr(),
700            },
701            Err(tce) => BalanceIdentifierPurseResult::Failure(tce),
702        }
703    }
704
705    /// Balance inquiry.
706    fn balance(&self, request: BalanceRequest) -> BalanceResult {
707        let mut tc = match self.tracking_copy(request.state_hash()) {
708            Ok(Some(tracking_copy)) => tracking_copy,
709            Ok(None) => return BalanceResult::RootNotFound,
710            Err(err) => return TrackingCopyError::Storage(err).into(),
711        };
712        let protocol_version = request.protocol_version();
713        let balance_identifier = request.identifier();
714        let purse_key = match balance_identifier.purse_uref(&mut tc, protocol_version) {
715            Ok(value) => value.into(),
716            Err(tce) => return tce.into(),
717        };
718        let (purse_balance_key, purse_addr) = match tc.get_purse_balance_key(purse_key) {
719            Ok(key @ Key::Balance(addr)) => (key, addr),
720            Ok(key) => return TrackingCopyError::UnexpectedKeyVariant(key).into(),
721            Err(tce) => return tce.into(),
722        };
723
724        let (total_balance, proofs_result) = match request.proof_handling() {
725            ProofHandling::NoProofs => {
726                let total_balance = match tc.read(&purse_balance_key) {
727                    Ok(Some(StoredValue::CLValue(cl_value))) => match cl_value.into_t::<U512>() {
728                        Ok(val) => val,
729                        Err(cve) => return TrackingCopyError::CLValue(cve).into(),
730                    },
731                    Ok(Some(_)) => return TrackingCopyError::UnexpectedStoredValueVariant.into(),
732                    Ok(None) => return TrackingCopyError::KeyNotFound(purse_balance_key).into(),
733                    Err(tce) => return tce.into(),
734                };
735                let balance_holds = match request.balance_handling() {
736                    BalanceHandling::Total => BTreeMap::new(),
737                    BalanceHandling::Available => {
738                        match tc.get_balance_hold_config(BalanceHoldAddrTag::Gas) {
739                            Ok(Some((block_time, _, interval))) => {
740                                match tc.get_balance_holds(purse_addr, block_time, interval) {
741                                    Ok(holds) => holds,
742                                    Err(tce) => return tce.into(),
743                                }
744                            }
745                            Ok(None) => BTreeMap::new(),
746                            Err(tce) => return tce.into(),
747                        }
748                    }
749                };
750                (total_balance, ProofsResult::NotRequested { balance_holds })
751            }
752            ProofHandling::Proofs => {
753                let (total_balance, total_balance_proof) =
754                    match tc.get_total_balance_with_proof(purse_balance_key) {
755                        Ok((balance, proof)) => (balance, Box::new(proof)),
756                        Err(tce) => return tce.into(),
757                    };
758
759                let balance_holds = match request.balance_handling() {
760                    BalanceHandling::Total => BTreeMap::new(),
761                    BalanceHandling::Available => {
762                        match tc.get_balance_holds_with_proof(purse_addr) {
763                            Ok(holds) => holds,
764                            Err(tce) => return tce.into(),
765                        }
766                    }
767                };
768
769                (
770                    total_balance,
771                    ProofsResult::Proofs {
772                        total_balance_proof,
773                        balance_holds,
774                    },
775                )
776            }
777        };
778
779        let (block_time, gas_hold_handling) = match tc
780            .get_balance_hold_config(BalanceHoldAddrTag::Gas)
781        {
782            Ok(Some((block_time, handling, interval))) => (block_time, (handling, interval).into()),
783            Ok(None) => {
784                return BalanceResult::Success {
785                    purse_addr,
786                    total_balance,
787                    available_balance: total_balance,
788                    proofs_result,
789                };
790            }
791            Err(tce) => return tce.into(),
792        };
793
794        let processing_hold_handling =
795            match tc.get_balance_hold_config(BalanceHoldAddrTag::Processing) {
796                Ok(Some((_, handling, interval))) => (handling, interval).into(),
797                Ok(None) => {
798                    return BalanceResult::Success {
799                        purse_addr,
800                        total_balance,
801                        available_balance: total_balance,
802                        proofs_result,
803                    };
804                }
805                Err(tce) => return tce.into(),
806            };
807
808        let available_balance = match &proofs_result.available_balance(
809            block_time,
810            total_balance,
811            gas_hold_handling,
812            processing_hold_handling,
813        ) {
814            Ok(available_balance) => *available_balance,
815            Err(be) => return BalanceResult::Failure(TrackingCopyError::Balance(be.clone())),
816        };
817
818        BalanceResult::Success {
819            purse_addr,
820            total_balance,
821            available_balance,
822            proofs_result,
823        }
824    }
825
826    /// Balance hold.
827    fn balance_hold(&self, request: BalanceHoldRequest) -> BalanceHoldResult {
828        let mut tc = match self.tracking_copy(request.state_hash()) {
829            Ok(Some(tracking_copy)) => tracking_copy,
830            Ok(None) => return BalanceHoldResult::RootNotFound,
831            Err(err) => {
832                return BalanceHoldResult::Failure(BalanceHoldError::TrackingCopy(
833                    TrackingCopyError::Storage(err),
834                ));
835            }
836        };
837        let hold_mode = request.balance_hold_mode();
838        match hold_mode {
839            BalanceHoldMode::Hold {
840                identifier,
841                hold_amount,
842                insufficient_handling,
843            } => {
844                let block_time = match tc.get_block_time() {
845                    Ok(Some(block_time)) => block_time,
846                    Ok(None) => return BalanceHoldResult::BlockTimeNotFound,
847                    Err(tce) => return tce.into(),
848                };
849                let tag = match request.balance_hold_kind() {
850                    BalanceHoldKind::All => {
851                        return BalanceHoldResult::Failure(
852                            BalanceHoldError::UnexpectedWildcardVariant,
853                        );
854                    }
855                    BalanceHoldKind::Tag(tag) => tag,
856                };
857                let balance_request = BalanceRequest::new(
858                    request.state_hash(),
859                    request.protocol_version(),
860                    identifier,
861                    BalanceHandling::Available,
862                    ProofHandling::NoProofs,
863                );
864                let balance_result = self.balance(balance_request);
865                let (total_balance, remaining_balance, purse_addr) = match balance_result {
866                    BalanceResult::RootNotFound => return BalanceHoldResult::RootNotFound,
867                    BalanceResult::Failure(be) => return be.into(),
868                    BalanceResult::Success {
869                        total_balance,
870                        available_balance,
871                        purse_addr,
872                        ..
873                    } => (total_balance, available_balance, purse_addr),
874                };
875
876                let held_amount = {
877                    if remaining_balance >= hold_amount {
878                        // the purse has sufficient balance to fully cover the hold
879                        hold_amount
880                    } else if insufficient_handling == InsufficientBalanceHandling::Noop {
881                        // the purse has insufficient balance and the insufficient
882                        // balance handling mode is noop, so get out
883                        return BalanceHoldResult::Failure(BalanceHoldError::InsufficientBalance {
884                            remaining_balance,
885                        });
886                    } else {
887                        // currently this is always the default HoldRemaining variant.
888                        // the purse holder has insufficient balance to cover the hold,
889                        // but the system will put a hold on whatever balance remains.
890                        // this is basically punitive to block an edge case resource consumption
891                        // attack whereby a malicious purse holder drains a balance to not-zero
892                        // but not-enough-to-cover-holds and then spams a bunch of transactions
893                        // knowing that they will fail due to insufficient funds, but only
894                        // after making the system do the work of processing the balance
895                        // check without penalty to themselves.
896                        remaining_balance
897                    }
898                };
899
900                let balance_hold_addr = match tag {
901                    BalanceHoldAddrTag::Gas => BalanceHoldAddr::Gas {
902                        purse_addr,
903                        block_time,
904                    },
905                    BalanceHoldAddrTag::Processing => BalanceHoldAddr::Processing {
906                        purse_addr,
907                        block_time,
908                    },
909                };
910
911                let hold_key = Key::BalanceHold(balance_hold_addr);
912                let hold_value = match tc.get(&hold_key) {
913                    Ok(Some(StoredValue::CLValue(cl_value))) => {
914                        // There was a previous hold on this balance. We need to add the new hold to
915                        // the old one.
916                        match cl_value.clone().into_t::<U512>() {
917                            Ok(prev_hold) => prev_hold.saturating_add(held_amount),
918                            Err(cve) => {
919                                return BalanceHoldResult::Failure(BalanceHoldError::TrackingCopy(
920                                    TrackingCopyError::CLValue(cve),
921                                ));
922                            }
923                        }
924                    }
925                    Ok(Some(other_value_variant)) => {
926                        return BalanceHoldResult::Failure(BalanceHoldError::UnexpectedHoldValue(
927                            other_value_variant,
928                        ))
929                    }
930                    Ok(None) => held_amount, // There was no previous hold.
931                    Err(tce) => {
932                        return BalanceHoldResult::Failure(BalanceHoldError::TrackingCopy(tce));
933                    }
934                };
935
936                let hold_cl_value = match CLValue::from_t(hold_value) {
937                    Ok(cl_value) => cl_value,
938                    Err(cve) => {
939                        return BalanceHoldResult::Failure(BalanceHoldError::TrackingCopy(
940                            TrackingCopyError::CLValue(cve),
941                        ));
942                    }
943                };
944                tc.write(hold_key, StoredValue::CLValue(hold_cl_value));
945                let holds = vec![balance_hold_addr];
946
947                let available_balance = remaining_balance.saturating_sub(held_amount);
948                let effects = tc.effects();
949                BalanceHoldResult::success(
950                    Some(holds),
951                    total_balance,
952                    available_balance,
953                    hold_amount,
954                    held_amount,
955                    effects,
956                )
957            }
958            BalanceHoldMode::Clear { identifier } => {
959                let purse_addr = match identifier.purse_uref(&mut tc, request.protocol_version()) {
960                    Ok(source_purse) => source_purse.addr(),
961                    Err(tce) => {
962                        return BalanceHoldResult::Failure(BalanceHoldError::TrackingCopy(tce));
963                    }
964                };
965
966                {
967                    // clear holds
968                    let hold_kind = request.balance_hold_kind();
969                    let mut filter = vec![];
970                    let tag = BalanceHoldAddrTag::Processing;
971                    if hold_kind.matches(tag) {
972                        let (block_time, interval) = match tc.get_balance_hold_config(tag) {
973                            Ok(Some((block_time, _, interval))) => (block_time, interval),
974                            Ok(None) => {
975                                return BalanceHoldResult::BlockTimeNotFound;
976                            }
977                            Err(tce) => {
978                                return BalanceHoldResult::Failure(BalanceHoldError::TrackingCopy(
979                                    tce,
980                                ));
981                            }
982                        };
983                        filter.push((tag, HoldsEpoch::from_millis(block_time.value(), interval)));
984                    }
985                    let tag = BalanceHoldAddrTag::Gas;
986                    if hold_kind.matches(tag) {
987                        let (block_time, interval) = match tc.get_balance_hold_config(tag) {
988                            Ok(Some((block_time, _, interval))) => (block_time, interval),
989                            Ok(None) => {
990                                return BalanceHoldResult::BlockTimeNotFound;
991                            }
992                            Err(tce) => {
993                                return BalanceHoldResult::Failure(BalanceHoldError::TrackingCopy(
994                                    tce,
995                                ));
996                            }
997                        };
998                        filter.push((tag, HoldsEpoch::from_millis(block_time.value(), interval)));
999                    }
1000                    if let Err(tce) = tc.clear_expired_balance_holds(purse_addr, filter) {
1001                        return BalanceHoldResult::Failure(BalanceHoldError::TrackingCopy(tce));
1002                    }
1003                }
1004
1005                // get updated balance
1006                let balance_result = self.balance(BalanceRequest::new(
1007                    request.state_hash(),
1008                    request.protocol_version(),
1009                    identifier,
1010                    BalanceHandling::Available,
1011                    ProofHandling::NoProofs,
1012                ));
1013                let (total_balance, available_balance) = match balance_result {
1014                    BalanceResult::RootNotFound => return BalanceHoldResult::RootNotFound,
1015                    BalanceResult::Failure(be) => return be.into(),
1016                    BalanceResult::Success {
1017                        total_balance,
1018                        available_balance,
1019                        ..
1020                    } => (total_balance, available_balance),
1021                };
1022                // note that hold & held in this context does not refer to remaining holds,
1023                // but rather to the requested hold amount and the resulting held amount for
1024                // this execution. as calls to this variant clears holds and does not create
1025                // new holds, hold & held are zero and no new hold address exists.
1026                let new_hold_addr = None;
1027                let hold = U512::zero();
1028                let held = U512::zero();
1029                let effects = tc.effects();
1030                BalanceHoldResult::success(
1031                    new_hold_addr,
1032                    total_balance,
1033                    available_balance,
1034                    hold,
1035                    held,
1036                    effects,
1037                )
1038            }
1039        }
1040    }
1041
1042    /// Get the requested era validators.
1043    fn era_validators(&self, request: EraValidatorsRequest) -> EraValidatorsResult {
1044        match self.seigniorage_recipients(SeigniorageRecipientsRequest::new(request.state_hash())) {
1045            SeigniorageRecipientsResult::RootNotFound => EraValidatorsResult::RootNotFound,
1046            SeigniorageRecipientsResult::Failure(err) => EraValidatorsResult::Failure(err),
1047            SeigniorageRecipientsResult::ValueNotFound(msg) => {
1048                EraValidatorsResult::ValueNotFound(msg)
1049            }
1050            SeigniorageRecipientsResult::AuctionNotFound => EraValidatorsResult::AuctionNotFound,
1051            SeigniorageRecipientsResult::Success {
1052                seigniorage_recipients,
1053            } => {
1054                let era_validators = match seigniorage_recipients {
1055                    SeigniorageRecipientsSnapshot::V1(snapshot) => {
1056                        auction::detail::era_validators_from_legacy_snapshot(snapshot)
1057                    }
1058                    SeigniorageRecipientsSnapshot::V2(snapshot) => {
1059                        auction::detail::era_validators_from_snapshot(snapshot)
1060                    }
1061                };
1062                EraValidatorsResult::Success { era_validators }
1063            }
1064        }
1065    }
1066
1067    /// Get the requested seigniorage recipients.
1068    fn seigniorage_recipients(
1069        &self,
1070        request: SeigniorageRecipientsRequest,
1071    ) -> SeigniorageRecipientsResult {
1072        let state_hash = request.state_hash();
1073        let tc = match self.tracking_copy(state_hash) {
1074            Ok(Some(tc)) => tc,
1075            Ok(None) => return SeigniorageRecipientsResult::RootNotFound,
1076            Err(err) => {
1077                return SeigniorageRecipientsResult::Failure(TrackingCopyError::Storage(err))
1078            }
1079        };
1080        let scr = match tc.get_system_entity_registry() {
1081            Ok(scr) => scr,
1082            Err(err) => return SeigniorageRecipientsResult::Failure(err),
1083        };
1084        let enable_addressable_entity = tc.enable_addressable_entity();
1085        match get_snapshot_data(self, &scr, state_hash, enable_addressable_entity) {
1086            not_found @ SeigniorageRecipientsResult::ValueNotFound(_) => {
1087                if enable_addressable_entity {
1088                    //There is a chance that, when looking for systemic data, we could be using a
1089                    // state root hash from before the AddressableEntity
1090                    // migration boundary. In such a case, we should attempt to look up the data
1091                    // under the Account/Contract model instead; e.g. Key::Hash instead of
1092                    // Key::AddressableEntity
1093                    match get_snapshot_data(self, &scr, state_hash, false) {
1094                        SeigniorageRecipientsResult::ValueNotFound(_) => not_found,
1095                        other => other,
1096                    }
1097                } else {
1098                    not_found
1099                }
1100            }
1101            other => other,
1102        }
1103    }
1104
1105    /// Gets the bids.
1106    fn bids(&self, request: BidsRequest) -> BidsResult {
1107        let state_hash = request.state_hash();
1108        let mut tc = match self.tracking_copy(state_hash) {
1109            Ok(Some(tc)) => tc,
1110            Ok(None) => return BidsResult::RootNotFound,
1111            Err(err) => return BidsResult::Failure(TrackingCopyError::Storage(err)),
1112        };
1113
1114        let bid_keys = match tc.get_keys(&KeyTag::BidAddr) {
1115            Ok(ret) => ret,
1116            Err(err) => return BidsResult::Failure(err),
1117        };
1118
1119        let mut bids = vec![];
1120        for key in bid_keys.iter() {
1121            match tc.get(key) {
1122                Ok(ret) => match ret {
1123                    Some(StoredValue::BidKind(bid_kind)) => {
1124                        if !bids.contains(&bid_kind) {
1125                            bids.push(bid_kind);
1126                        }
1127                    }
1128                    Some(_) => {
1129                        return BidsResult::Failure(
1130                            TrackingCopyError::UnexpectedStoredValueVariant,
1131                        );
1132                    }
1133                    None => return BidsResult::Failure(TrackingCopyError::MissingBid(*key)),
1134                },
1135                Err(error) => return BidsResult::Failure(error),
1136            }
1137        }
1138        BidsResult::Success { bids }
1139    }
1140
1141    /// Direct auction interaction for all variations of bid management.
1142    fn bidding(
1143        &self,
1144        BiddingRequest {
1145            config,
1146            state_hash,
1147            protocol_version,
1148            auction_method,
1149            transaction_hash,
1150            initiator,
1151            authorization_keys,
1152        }: BiddingRequest,
1153    ) -> BiddingResult {
1154        let tc = match self.tracking_copy(state_hash) {
1155            Ok(Some(tc)) => Rc::new(RefCell::new(tc)),
1156            Ok(None) => return BiddingResult::RootNotFound,
1157            Err(err) => return BiddingResult::Failure(TrackingCopyError::Storage(err)),
1158        };
1159
1160        let source_account_hash = initiator.account_hash();
1161        let (entity_addr, mut footprint, mut entity_access_rights) = match tc
1162            .borrow_mut()
1163            .authorized_runtime_footprint_with_access_rights(
1164                protocol_version,
1165                source_account_hash,
1166                &authorization_keys,
1167                &BTreeSet::default(),
1168            ) {
1169            Ok(ret) => ret,
1170            Err(tce) => {
1171                return BiddingResult::Failure(tce);
1172            }
1173        };
1174        let entity_key = Key::AddressableEntity(entity_addr);
1175
1176        // extend named keys with era end timestamp
1177        match tc
1178            .borrow_mut()
1179            .system_contract_named_key(AUCTION, ERA_END_TIMESTAMP_MILLIS_KEY)
1180        {
1181            Ok(Some(k)) => {
1182                match k.as_uref() {
1183                    Some(uref) => entity_access_rights.extend(&[*uref]),
1184                    None => {
1185                        return BiddingResult::Failure(TrackingCopyError::UnexpectedKeyVariant(k));
1186                    }
1187                }
1188                footprint.insert_into_named_keys(ERA_END_TIMESTAMP_MILLIS_KEY.into(), k);
1189            }
1190            Ok(None) => {
1191                return BiddingResult::Failure(TrackingCopyError::NamedKeyNotFound(
1192                    ERA_END_TIMESTAMP_MILLIS_KEY.into(),
1193                ));
1194            }
1195            Err(tce) => {
1196                return BiddingResult::Failure(tce);
1197            }
1198        };
1199        // extend named keys with era id
1200        match tc
1201            .borrow_mut()
1202            .system_contract_named_key(AUCTION, ERA_ID_KEY)
1203        {
1204            Ok(Some(k)) => {
1205                match k.as_uref() {
1206                    Some(uref) => entity_access_rights.extend(&[*uref]),
1207                    None => {
1208                        return BiddingResult::Failure(TrackingCopyError::UnexpectedKeyVariant(k));
1209                    }
1210                }
1211                footprint.insert_into_named_keys(ERA_ID_KEY.into(), k);
1212            }
1213            Ok(None) => {
1214                return BiddingResult::Failure(TrackingCopyError::NamedKeyNotFound(
1215                    ERA_ID_KEY.into(),
1216                ));
1217            }
1218            Err(tce) => {
1219                return BiddingResult::Failure(tce);
1220            }
1221        };
1222
1223        let phase = Phase::Session;
1224        let id = Id::Transaction(transaction_hash);
1225        let address_generator = AddressGenerator::new(&id.seed(), phase);
1226        let max_delegators_per_validator = config.max_delegators_per_validator();
1227        let minimum_bid_amount = config.minimum_bid_amount();
1228        let mut runtime = RuntimeNative::new(
1229            config,
1230            protocol_version,
1231            id,
1232            Arc::new(RwLock::new(address_generator)),
1233            Rc::clone(&tc),
1234            source_account_hash,
1235            entity_key,
1236            footprint,
1237            entity_access_rights,
1238            U512::MAX,
1239            phase,
1240        );
1241
1242        let result = match auction_method {
1243            AuctionMethod::ActivateBid { validator } => runtime
1244                .activate_bid(validator, minimum_bid_amount)
1245                .map(|_| AuctionMethodRet::Unit)
1246                .map_err(|auc_err| {
1247                    TrackingCopyError::SystemContract(system::Error::Auction(auc_err))
1248                }),
1249            AuctionMethod::AddBid {
1250                public_key,
1251                delegation_rate,
1252                amount,
1253                minimum_delegation_amount,
1254                maximum_delegation_amount,
1255                minimum_bid_amount,
1256                reserved_slots,
1257            } => runtime
1258                .add_bid(
1259                    public_key,
1260                    delegation_rate,
1261                    amount,
1262                    minimum_delegation_amount,
1263                    maximum_delegation_amount,
1264                    minimum_bid_amount,
1265                    max_delegators_per_validator,
1266                    reserved_slots,
1267                )
1268                .map(AuctionMethodRet::UpdatedAmount)
1269                .map_err(TrackingCopyError::Api),
1270            AuctionMethod::WithdrawBid {
1271                public_key,
1272                amount,
1273                minimum_bid_amount,
1274            } => runtime
1275                .withdraw_bid(public_key, amount, minimum_bid_amount)
1276                .map(AuctionMethodRet::UpdatedAmount)
1277                .map_err(|auc_err| {
1278                    TrackingCopyError::SystemContract(system::Error::Auction(auc_err))
1279                }),
1280            AuctionMethod::Delegate {
1281                delegator,
1282                validator,
1283                amount,
1284                max_delegators_per_validator,
1285            } => runtime
1286                .delegate(delegator, validator, amount, max_delegators_per_validator)
1287                .map(AuctionMethodRet::UpdatedAmount)
1288                .map_err(TrackingCopyError::Api),
1289            AuctionMethod::Undelegate {
1290                delegator,
1291                validator,
1292                amount,
1293            } => runtime
1294                .undelegate(delegator, validator, amount)
1295                .map(AuctionMethodRet::UpdatedAmount)
1296                .map_err(|auc_err| {
1297                    TrackingCopyError::SystemContract(system::Error::Auction(auc_err))
1298                }),
1299            AuctionMethod::Redelegate {
1300                delegator,
1301                validator,
1302                amount,
1303                new_validator,
1304            } => runtime
1305                .redelegate(delegator, validator, amount, new_validator)
1306                .map(AuctionMethodRet::UpdatedAmount)
1307                .map_err(|auc_err| {
1308                    TrackingCopyError::SystemContract(system::Error::Auction(auc_err))
1309                }),
1310            AuctionMethod::ChangeBidPublicKey {
1311                public_key,
1312                new_public_key,
1313            } => runtime
1314                .change_bid_public_key(public_key, new_public_key)
1315                .map(|_| AuctionMethodRet::Unit)
1316                .map_err(|auc_err| {
1317                    TrackingCopyError::SystemContract(system::Error::Auction(auc_err))
1318                }),
1319            AuctionMethod::AddReservations { reservations } => runtime
1320                .add_reservations(reservations)
1321                .map(|_| AuctionMethodRet::Unit)
1322                .map_err(|auc_err| {
1323                    TrackingCopyError::SystemContract(system::Error::Auction(auc_err))
1324                }),
1325            AuctionMethod::CancelReservations {
1326                validator,
1327                delegators,
1328                max_delegators_per_validator,
1329            } => runtime
1330                .cancel_reservations(validator, delegators, max_delegators_per_validator)
1331                .map(|_| AuctionMethodRet::Unit)
1332                .map_err(|auc_err| {
1333                    TrackingCopyError::SystemContract(system::Error::Auction(auc_err))
1334                }),
1335        };
1336
1337        let transfers = runtime.into_transfers();
1338        let effects = tc.borrow_mut().effects();
1339
1340        match result {
1341            Ok(ret) => BiddingResult::Success {
1342                ret,
1343                effects,
1344                transfers,
1345            },
1346            Err(tce) => BiddingResult::Failure(tce),
1347        }
1348    }
1349
1350    /// Handle refund.
1351    fn handle_refund(
1352        &self,
1353        HandleRefundRequest {
1354            config,
1355            state_hash,
1356            protocol_version,
1357            transaction_hash,
1358            refund_mode,
1359        }: HandleRefundRequest,
1360    ) -> HandleRefundResult {
1361        let tc = match self.tracking_copy(state_hash) {
1362            Ok(Some(tc)) => Rc::new(RefCell::new(tc)),
1363            Ok(None) => return HandleRefundResult::RootNotFound,
1364            Err(err) => return HandleRefundResult::Failure(TrackingCopyError::Storage(err)),
1365        };
1366
1367        let id = Id::Transaction(transaction_hash);
1368        let phase = refund_mode.phase();
1369        let address_generator = Arc::new(RwLock::new(AddressGenerator::new(&id.seed(), phase)));
1370        let mut runtime = match phase {
1371            Phase::FinalizePayment => {
1372                // this runtime uses the system's context
1373                match RuntimeNative::new_system_runtime(
1374                    config,
1375                    protocol_version,
1376                    id,
1377                    address_generator,
1378                    Rc::clone(&tc),
1379                    phase,
1380                ) {
1381                    Ok(rt) => rt,
1382                    Err(tce) => {
1383                        return HandleRefundResult::Failure(tce);
1384                    }
1385                }
1386            }
1387            Phase::Payment => {
1388                // this runtime uses the handle payment contract's context
1389                match RuntimeNative::new_system_contract_runtime(
1390                    config,
1391                    protocol_version,
1392                    id,
1393                    address_generator,
1394                    Rc::clone(&tc),
1395                    phase,
1396                    HANDLE_PAYMENT,
1397                ) {
1398                    Ok(rt) => rt,
1399                    Err(tce) => {
1400                        return HandleRefundResult::Failure(tce);
1401                    }
1402                }
1403            }
1404            Phase::System | Phase::Session => return HandleRefundResult::InvalidPhase,
1405        };
1406
1407        let result = match refund_mode {
1408            HandleRefundMode::CalculateAmount {
1409                limit,
1410                cost,
1411                gas_price,
1412                consumed,
1413                ratio,
1414                source,
1415            } => {
1416                let source_purse = match source.purse_uref(&mut tc.borrow_mut(), protocol_version) {
1417                    Ok(value) => value,
1418                    Err(tce) => return HandleRefundResult::Failure(tce),
1419                };
1420                let (numer, denom) = ratio.into();
1421                let ratio = Ratio::new_raw(U512::from(numer), U512::from(denom));
1422                let refund_amount = match runtime.calculate_overpayment_and_fee(
1423                    limit,
1424                    gas_price,
1425                    cost,
1426                    consumed,
1427                    source_purse,
1428                    ratio,
1429                ) {
1430                    Ok((refund, _)) => Some(refund),
1431                    Err(hpe) => {
1432                        return HandleRefundResult::Failure(TrackingCopyError::SystemContract(
1433                            system::Error::HandlePayment(hpe),
1434                        ));
1435                    }
1436                };
1437                Ok(refund_amount)
1438            }
1439            HandleRefundMode::Refund {
1440                initiator_addr,
1441                limit,
1442                cost,
1443                gas_price,
1444                consumed,
1445                ratio,
1446                source,
1447                target,
1448            } => {
1449                let source_purse = match source.purse_uref(&mut tc.borrow_mut(), protocol_version) {
1450                    Ok(value) => value,
1451                    Err(tce) => return HandleRefundResult::Failure(tce),
1452                };
1453                let (numer, denom) = ratio.into();
1454                let ratio = Ratio::new_raw(U512::from(numer), U512::from(denom));
1455                let refund_amount = match runtime.calculate_overpayment_and_fee(
1456                    limit,
1457                    gas_price,
1458                    cost,
1459                    consumed,
1460                    source_purse,
1461                    ratio,
1462                ) {
1463                    Ok((refund, _)) => refund,
1464                    Err(hpe) => {
1465                        return HandleRefundResult::Failure(TrackingCopyError::SystemContract(
1466                            system::Error::HandlePayment(hpe),
1467                        ));
1468                    }
1469                };
1470                let target_purse = match target.purse_uref(&mut tc.borrow_mut(), protocol_version) {
1471                    Ok(value) => value,
1472                    Err(tce) => return HandleRefundResult::Failure(tce),
1473                };
1474                // pay amount from source to target
1475                match runtime
1476                    .transfer(
1477                        Some(initiator_addr.account_hash()),
1478                        source_purse,
1479                        target_purse,
1480                        refund_amount,
1481                        None,
1482                    )
1483                    .map_err(|mint_err| {
1484                        TrackingCopyError::SystemContract(system::Error::Mint(mint_err))
1485                    }) {
1486                    Ok(_) => Ok(Some(refund_amount)),
1487                    Err(err) => Err(err),
1488                }
1489            }
1490            HandleRefundMode::RefundNoFeeCustomPayment {
1491                initiator_addr,
1492                limit,
1493                cost,
1494                gas_price,
1495            } => {
1496                let source = BalanceIdentifier::Payment;
1497                let source_purse = match source.purse_uref(&mut tc.borrow_mut(), protocol_version) {
1498                    Ok(value) => value,
1499                    Err(tce) => return HandleRefundResult::Failure(tce),
1500                };
1501                let consumed = U512::zero();
1502                let ratio = Ratio::new_raw(U512::one(), U512::one());
1503                let refund_amount = match runtime.calculate_overpayment_and_fee(
1504                    limit,
1505                    gas_price,
1506                    cost,
1507                    consumed,
1508                    source_purse,
1509                    ratio,
1510                ) {
1511                    Ok((refund, _)) => refund,
1512                    Err(hpe) => {
1513                        return HandleRefundResult::Failure(TrackingCopyError::SystemContract(
1514                            system::Error::HandlePayment(hpe),
1515                        ));
1516                    }
1517                };
1518                let target = BalanceIdentifier::Refund;
1519                let target_purse = match target.purse_uref(&mut tc.borrow_mut(), protocol_version) {
1520                    Ok(value) => value,
1521                    Err(tce) => return HandleRefundResult::Failure(tce),
1522                };
1523                match runtime
1524                    .transfer(
1525                        Some(initiator_addr.account_hash()),
1526                        source_purse,
1527                        target_purse,
1528                        refund_amount,
1529                        None,
1530                    )
1531                    .map_err(|mint_err| {
1532                        TrackingCopyError::SystemContract(system::Error::Mint(mint_err))
1533                    }) {
1534                    Ok(_) => Ok(Some(U512::zero())), // return 0 in this mode
1535                    Err(err) => Err(err),
1536                }
1537            }
1538            HandleRefundMode::Burn {
1539                limit,
1540                gas_price,
1541                cost,
1542                consumed,
1543                source,
1544                ratio,
1545            } => {
1546                let source_purse = match source.purse_uref(&mut tc.borrow_mut(), protocol_version) {
1547                    Ok(value) => value,
1548                    Err(tce) => return HandleRefundResult::Failure(tce),
1549                };
1550                let (numer, denom) = ratio.into();
1551                let ratio = Ratio::new_raw(U512::from(numer), U512::from(denom));
1552                let burn_amount = match runtime.calculate_overpayment_and_fee(
1553                    limit,
1554                    gas_price,
1555                    cost,
1556                    consumed,
1557                    source_purse,
1558                    ratio,
1559                ) {
1560                    Ok((amount, _)) => Some(amount),
1561                    Err(hpe) => {
1562                        return HandleRefundResult::Failure(TrackingCopyError::SystemContract(
1563                            system::Error::HandlePayment(hpe),
1564                        ));
1565                    }
1566                };
1567                match runtime.payment_burn(source_purse, burn_amount) {
1568                    Ok(_) => Ok(burn_amount),
1569                    Err(hpe) => Err(TrackingCopyError::SystemContract(
1570                        system::Error::HandlePayment(hpe),
1571                    )),
1572                }
1573            }
1574            HandleRefundMode::SetRefundPurse { target } => {
1575                let target_purse = match target.purse_uref(&mut tc.borrow_mut(), protocol_version) {
1576                    Ok(value) => value,
1577                    Err(tce) => return HandleRefundResult::Failure(tce),
1578                };
1579                match runtime.set_refund_purse(target_purse) {
1580                    Ok(_) => Ok(None),
1581                    Err(hpe) => Err(TrackingCopyError::SystemContract(
1582                        system::Error::HandlePayment(hpe),
1583                    )),
1584                }
1585            }
1586            HandleRefundMode::ClearRefundPurse => match runtime.clear_refund_purse() {
1587                Ok(_) => Ok(None),
1588                Err(hpe) => Err(TrackingCopyError::SystemContract(
1589                    system::Error::HandlePayment(hpe),
1590                )),
1591            },
1592        };
1593
1594        let effects = tc.borrow_mut().effects();
1595        let transfers = runtime.into_transfers();
1596
1597        match result {
1598            Ok(amount) => HandleRefundResult::Success {
1599                transfers,
1600                effects,
1601                amount,
1602            },
1603            Err(tce) => HandleRefundResult::Failure(tce),
1604        }
1605    }
1606
1607    /// Handle payment.
1608    fn handle_fee(
1609        &self,
1610        HandleFeeRequest {
1611            config,
1612            state_hash,
1613            protocol_version,
1614            transaction_hash,
1615            handle_fee_mode,
1616        }: HandleFeeRequest,
1617    ) -> HandleFeeResult {
1618        let tc = match self.tracking_copy(state_hash) {
1619            Ok(Some(tc)) => Rc::new(RefCell::new(tc)),
1620            Ok(None) => return HandleFeeResult::RootNotFound,
1621            Err(err) => return HandleFeeResult::Failure(TrackingCopyError::Storage(err)),
1622        };
1623
1624        // this runtime uses the system's context
1625
1626        let id = Id::Transaction(transaction_hash);
1627        let phase = Phase::FinalizePayment;
1628        let address_generator = AddressGenerator::new(&id.seed(), phase);
1629
1630        let mut runtime = match RuntimeNative::new_system_runtime(
1631            config,
1632            protocol_version,
1633            id,
1634            Arc::new(RwLock::new(address_generator)),
1635            Rc::clone(&tc),
1636            phase,
1637        ) {
1638            Ok(rt) => rt,
1639            Err(tce) => {
1640                return HandleFeeResult::Failure(tce);
1641            }
1642        };
1643
1644        let result = match handle_fee_mode {
1645            HandleFeeMode::Credit {
1646                validator,
1647                amount,
1648                era_id,
1649            } => runtime
1650                .write_validator_credit(*validator, era_id, amount)
1651                .map(|_| ())
1652                .map_err(|auction_error| {
1653                    TrackingCopyError::SystemContract(system::Error::Auction(auction_error))
1654                }),
1655            HandleFeeMode::Pay {
1656                initiator_addr,
1657                amount,
1658                source,
1659                target,
1660            } => {
1661                let source_purse = match source.purse_uref(&mut tc.borrow_mut(), protocol_version) {
1662                    Ok(value) => value,
1663                    Err(tce) => return HandleFeeResult::Failure(tce),
1664                };
1665                let target_purse = match target.purse_uref(&mut tc.borrow_mut(), protocol_version) {
1666                    Ok(value) => value,
1667                    Err(tce) => return HandleFeeResult::Failure(tce),
1668                };
1669                runtime
1670                    .transfer(
1671                        Some(initiator_addr.account_hash()),
1672                        source_purse,
1673                        target_purse,
1674                        amount,
1675                        None,
1676                    )
1677                    .map_err(|mint_err| {
1678                        TrackingCopyError::SystemContract(system::Error::Mint(mint_err))
1679                    })
1680            }
1681            HandleFeeMode::Burn { source, amount } => {
1682                let source_purse = match source.purse_uref(&mut tc.borrow_mut(), protocol_version) {
1683                    Ok(value) => value,
1684                    Err(tce) => return HandleFeeResult::Failure(tce),
1685                };
1686                runtime
1687                    .payment_burn(source_purse, amount)
1688                    .map_err(|handle_payment_error| {
1689                        TrackingCopyError::SystemContract(system::Error::HandlePayment(
1690                            handle_payment_error,
1691                        ))
1692                    })
1693            }
1694        };
1695
1696        let effects = tc.borrow_mut().effects();
1697        let transfers = runtime.into_transfers();
1698
1699        match result {
1700            Ok(_) => HandleFeeResult::Success { transfers, effects },
1701            Err(tce) => HandleFeeResult::Failure(tce),
1702        }
1703    }
1704
1705    /// Gets the execution result checksum.
1706    fn execution_result_checksum(
1707        &self,
1708        request: ExecutionResultsChecksumRequest,
1709    ) -> ExecutionResultsChecksumResult {
1710        let state_hash = request.state_hash();
1711        let mut tc = match self.tracking_copy(state_hash) {
1712            Ok(Some(tc)) => tc,
1713            Ok(None) => return ExecutionResultsChecksumResult::RootNotFound,
1714            Err(err) => {
1715                return ExecutionResultsChecksumResult::Failure(TrackingCopyError::Storage(err));
1716            }
1717        };
1718        match tc.get_checksum_registry() {
1719            Ok(Some(registry)) => match registry.get(EXECUTION_RESULTS_CHECKSUM_NAME) {
1720                Some(checksum) => ExecutionResultsChecksumResult::Success {
1721                    checksum: *checksum,
1722                },
1723                None => ExecutionResultsChecksumResult::ChecksumNotFound,
1724            },
1725            Ok(None) => ExecutionResultsChecksumResult::RegistryNotFound,
1726            Err(err) => ExecutionResultsChecksumResult::Failure(err),
1727        }
1728    }
1729
1730    /// Gets an addressable entity.
1731    fn addressable_entity(&self, request: AddressableEntityRequest) -> AddressableEntityResult {
1732        let key = request.key();
1733        let query_key = match key {
1734            Key::Account(_) => {
1735                let query_request = QueryRequest::new(request.state_hash(), key, vec![]);
1736                match self.query(query_request) {
1737                    QueryResult::RootNotFound => return AddressableEntityResult::RootNotFound,
1738                    QueryResult::ValueNotFound(msg) => {
1739                        return AddressableEntityResult::ValueNotFound(msg);
1740                    }
1741                    QueryResult::Failure(err) => return AddressableEntityResult::Failure(err),
1742                    QueryResult::Success { value, .. } => {
1743                        if let StoredValue::Account(account) = *value {
1744                            // legacy account that has not been migrated
1745                            let entity = AddressableEntity::from(account);
1746                            return AddressableEntityResult::Success { entity };
1747                        }
1748                        if let StoredValue::CLValue(cl_value) = &*value {
1749                            // the corresponding entity key should be under the account's key
1750                            match cl_value.clone().into_t::<Key>() {
1751                                Ok(entity_key @ Key::AddressableEntity(_)) => entity_key,
1752                                Ok(invalid_key) => {
1753                                    warn!(
1754                                        %key,
1755                                        %invalid_key,
1756                                        type_name = %value.type_name(),
1757                                        "expected a Key::AddressableEntity to be stored under account hash"
1758                                    );
1759                                    return AddressableEntityResult::Failure(
1760                                        TrackingCopyError::UnexpectedStoredValueVariant,
1761                                    );
1762                                }
1763                                Err(error) => {
1764                                    error!(%key, %error, "expected a CLValue::Key to be stored under account hash");
1765                                    return AddressableEntityResult::Failure(
1766                                        TrackingCopyError::CLValue(error),
1767                                    );
1768                                }
1769                            }
1770                        } else {
1771                            warn!(
1772                                %key,
1773                                type_name = %value.type_name(),
1774                                "expected a CLValue::Key or Account to be stored under account hash"
1775                            );
1776                            return AddressableEntityResult::Failure(
1777                                TrackingCopyError::UnexpectedStoredValueVariant,
1778                            );
1779                        }
1780                    }
1781                }
1782            }
1783            Key::Hash(contract_hash) => {
1784                let query_request = QueryRequest::new(request.state_hash(), key, vec![]);
1785                match self.query(query_request) {
1786                    QueryResult::RootNotFound => return AddressableEntityResult::RootNotFound,
1787                    QueryResult::ValueNotFound(msg) => {
1788                        return AddressableEntityResult::ValueNotFound(msg);
1789                    }
1790                    QueryResult::Failure(err) => return AddressableEntityResult::Failure(err),
1791                    QueryResult::Success { value, .. } => {
1792                        if let StoredValue::Contract(contract) = *value {
1793                            // legacy contract that has not been migrated
1794                            let entity = AddressableEntity::from(contract);
1795                            return AddressableEntityResult::Success { entity };
1796                        }
1797                        Key::AddressableEntity(EntityAddr::SmartContract(contract_hash))
1798                    }
1799                }
1800            }
1801            Key::AddressableEntity(_) => key,
1802            _ => {
1803                return AddressableEntityResult::Failure(TrackingCopyError::UnexpectedKeyVariant(
1804                    key,
1805                ));
1806            }
1807        };
1808
1809        let query_request = QueryRequest::new(request.state_hash(), query_key, vec![]);
1810        match self.query(query_request) {
1811            QueryResult::RootNotFound => AddressableEntityResult::RootNotFound,
1812            QueryResult::ValueNotFound(msg) => AddressableEntityResult::ValueNotFound(msg),
1813            QueryResult::Success { value, .. } => {
1814                let entity = match value.as_addressable_entity() {
1815                    Some(entity) => entity.clone(),
1816                    None => {
1817                        return AddressableEntityResult::Failure(
1818                            TrackingCopyError::UnexpectedStoredValueVariant,
1819                        );
1820                    }
1821                };
1822                AddressableEntityResult::Success { entity }
1823            }
1824            QueryResult::Failure(err) => AddressableEntityResult::Failure(err),
1825        }
1826    }
1827
1828    /// Returns the system entity registry or the key for a system entity registered within it.
1829    fn system_entity_registry(
1830        &self,
1831        request: SystemEntityRegistryRequest,
1832    ) -> SystemEntityRegistryResult {
1833        let state_hash = request.state_hash();
1834        let tc = match self.tracking_copy(state_hash) {
1835            Ok(Some(tc)) => tc,
1836            Ok(None) => return SystemEntityRegistryResult::RootNotFound,
1837            Err(err) => {
1838                return SystemEntityRegistryResult::Failure(TrackingCopyError::Storage(err));
1839            }
1840        };
1841
1842        let reg = match tc.get_system_entity_registry() {
1843            Ok(reg) => reg,
1844            Err(tce) => {
1845                return SystemEntityRegistryResult::Failure(tce);
1846            }
1847        };
1848
1849        let selector = request.selector();
1850        match selector {
1851            SystemEntityRegistrySelector::All => SystemEntityRegistryResult::Success {
1852                selected: selector.clone(),
1853                payload: SystemEntityRegistryPayload::All(reg),
1854            },
1855            SystemEntityRegistrySelector::ByName(name) => match reg.get(name).copied() {
1856                Some(entity_hash) => {
1857                    let key = if !request.enable_addressable_entity() {
1858                        Key::Hash(entity_hash)
1859                    } else {
1860                        Key::AddressableEntity(EntityAddr::System(entity_hash))
1861                    };
1862                    SystemEntityRegistryResult::Success {
1863                        selected: selector.clone(),
1864                        payload: SystemEntityRegistryPayload::EntityKey(key),
1865                    }
1866                }
1867                None => {
1868                    error!("unexpected query failure; mint not found");
1869                    SystemEntityRegistryResult::NamedEntityNotFound(name.clone())
1870                }
1871            },
1872        }
1873    }
1874
1875    /// Gets an entry point value.
1876    fn entry_point(&self, request: EntryPointRequest) -> EntryPointResult {
1877        let state_root_hash = request.state_hash();
1878        let contract_hash = request.contract_hash();
1879        let entry_point_name = request.entry_point_name();
1880        match EntryPointAddr::new_v1_entry_point_addr(
1881            EntityAddr::SmartContract(contract_hash),
1882            entry_point_name,
1883        ) {
1884            Ok(entry_point_addr) => {
1885                let key = Key::EntryPoint(entry_point_addr);
1886                let query_request = QueryRequest::new(request.state_hash(), key, vec![]);
1887                //We first check if the entry point exists as a stand alone 2.x entity
1888                match self.query(query_request) {
1889                    QueryResult::RootNotFound => EntryPointResult::RootNotFound,
1890                    QueryResult::ValueNotFound(query_result_not_found_msg) => {
1891                        //If the entry point was not found as a 2.x entity, we check if it exists
1892                        // as part of a 1.x contract
1893                        let contract_key = Key::Hash(contract_hash);
1894                        let contract_request = ContractRequest::new(state_root_hash, contract_key);
1895                        match self.contract(contract_request) {
1896                            ContractResult::Failure(tce) => EntryPointResult::Failure(tce),
1897                            ContractResult::ValueNotFound(_) => {
1898                                EntryPointResult::ValueNotFound(query_result_not_found_msg)
1899                            }
1900                            ContractResult::RootNotFound => EntryPointResult::RootNotFound,
1901                            ContractResult::Success { contract } => {
1902                                match contract.entry_points().get(entry_point_name) {
1903                                    Some(contract_entry_point) => EntryPointResult::Success {
1904                                        entry_point: EntryPointValue::V1CasperVm(
1905                                            EntityEntryPoint::from(contract_entry_point),
1906                                        ),
1907                                    },
1908                                    None => {
1909                                        EntryPointResult::ValueNotFound(query_result_not_found_msg)
1910                                    }
1911                                }
1912                            }
1913                        }
1914                    }
1915                    QueryResult::Failure(tce) => EntryPointResult::Failure(tce),
1916                    QueryResult::Success { value, .. } => {
1917                        if let StoredValue::EntryPoint(entry_point) = *value {
1918                            EntryPointResult::Success { entry_point }
1919                        } else {
1920                            error!("Expected to get entry point value received other variant");
1921                            EntryPointResult::Failure(
1922                                TrackingCopyError::UnexpectedStoredValueVariant,
1923                            )
1924                        }
1925                    }
1926                }
1927            }
1928            Err(_) => EntryPointResult::Failure(
1929                //TODO maybe we can have a better error type here
1930                TrackingCopyError::ValueNotFound("Entry point not found".to_string()),
1931            ),
1932        }
1933    }
1934
1935    /// Gets a contract value.
1936    fn contract(&self, request: ContractRequest) -> ContractResult {
1937        let query_request = QueryRequest::new(request.state_hash(), request.key(), vec![]);
1938
1939        match self.query(query_request) {
1940            QueryResult::RootNotFound => ContractResult::RootNotFound,
1941            QueryResult::ValueNotFound(msg) => ContractResult::ValueNotFound(msg),
1942            QueryResult::Failure(tce) => ContractResult::Failure(tce),
1943            QueryResult::Success { value, .. } => {
1944                if let StoredValue::Contract(contract) = *value {
1945                    ContractResult::Success { contract }
1946                } else {
1947                    error!("Expected to get contract value received other variant");
1948                    ContractResult::Failure(TrackingCopyError::UnexpectedStoredValueVariant)
1949                }
1950            }
1951        }
1952    }
1953
1954    /// Gets an entry point value.
1955    fn entry_point_exists(&self, request: EntryPointExistsRequest) -> EntryPointExistsResult {
1956        match self.entry_point(request.into()) {
1957            EntryPointResult::RootNotFound => EntryPointExistsResult::RootNotFound,
1958            EntryPointResult::ValueNotFound(msg) => EntryPointExistsResult::ValueNotFound(msg),
1959            EntryPointResult::Success { .. } => EntryPointExistsResult::Success,
1960            EntryPointResult::Failure(error) => EntryPointExistsResult::Failure(error),
1961        }
1962    }
1963
1964    /// Gets total supply.
1965    fn total_supply(&self, request: TotalSupplyRequest) -> TotalSupplyResult {
1966        let state_hash = request.state_hash();
1967        let tc = match self.tracking_copy(state_hash) {
1968            Ok(Some(tc)) => tc,
1969            Ok(None) => return TotalSupplyResult::RootNotFound,
1970            Err(err) => return TotalSupplyResult::Failure(TrackingCopyError::Storage(err)),
1971        };
1972        let scr = match tc.get_system_entity_registry() {
1973            Ok(scr) => scr,
1974            Err(err) => return TotalSupplyResult::Failure(err),
1975        };
1976        let enable_addressable_entity = tc.enable_addressable_entity();
1977        match get_total_supply_data(self, &scr, state_hash, enable_addressable_entity) {
1978            not_found @ TotalSupplyResult::ValueNotFound(_) => {
1979                if enable_addressable_entity {
1980                    //There is a chance that, when looking for systemic data, we could be using a
1981                    // state root hash from before the AddressableEntity
1982                    // migration boundary. In such a case, we should attempt to look up the data
1983                    // under the Account/Contract model instead; e.g. Key::Hash instead of
1984                    // Key::AddressableEntity
1985                    match get_total_supply_data(self, &scr, state_hash, false) {
1986                        TotalSupplyResult::ValueNotFound(_) => not_found,
1987                        other => other,
1988                    }
1989                } else {
1990                    not_found
1991                }
1992            }
1993            other => other,
1994        }
1995    }
1996
1997    /// Gets the current round seigniorage rate.
1998    fn round_seigniorage_rate(
1999        &self,
2000        request: RoundSeigniorageRateRequest,
2001    ) -> RoundSeigniorageRateResult {
2002        let state_hash = request.state_hash();
2003        let tc = match self.tracking_copy(state_hash) {
2004            Ok(Some(tc)) => tc,
2005            Ok(None) => return RoundSeigniorageRateResult::RootNotFound,
2006            Err(err) => {
2007                return RoundSeigniorageRateResult::Failure(TrackingCopyError::Storage(err));
2008            }
2009        };
2010        let scr = match tc.get_system_entity_registry() {
2011            Ok(scr) => scr,
2012            Err(err) => return RoundSeigniorageRateResult::Failure(err),
2013        };
2014        let enable_addressable_entity = tc.enable_addressable_entity();
2015        match get_round_seigniorage_rate_data(self, &scr, state_hash, enable_addressable_entity) {
2016            not_found @ RoundSeigniorageRateResult::ValueNotFound(_) => {
2017                if enable_addressable_entity {
2018                    //There is a chance that, when looking for systemic data, we could be using a
2019                    // state root hash from before the AddressableEntity
2020                    // migration boundary. In such a case, we should attempt to look up the data
2021                    // under the Account/Contract model instead; e.g. Key::Hash instead of
2022                    // Key::AddressableEntity
2023                    match get_round_seigniorage_rate_data(self, &scr, state_hash, false) {
2024                        RoundSeigniorageRateResult::ValueNotFound(_) => not_found,
2025                        other => other,
2026                    }
2027                } else {
2028                    not_found
2029                }
2030            }
2031            other => other,
2032        }
2033    }
2034
2035    /// Direct transfer.
2036    fn transfer(&self, request: TransferRequest) -> TransferResult {
2037        let state_hash = request.state_hash();
2038        let tc = match self.tracking_copy(state_hash) {
2039            Ok(Some(tc)) => Rc::new(RefCell::new(tc)),
2040            Ok(None) => return TransferResult::RootNotFound,
2041            Err(err) => {
2042                return TransferResult::Failure(TransferError::TrackingCopy(
2043                    TrackingCopyError::Storage(err),
2044                ));
2045            }
2046        };
2047
2048        let source_account_hash = request.initiator().account_hash();
2049        let protocol_version = request.protocol_version();
2050        if let Err(tce) = tc
2051            .borrow_mut()
2052            .migrate_account(source_account_hash, protocol_version)
2053        {
2054            return TransferResult::Failure(tce.into());
2055        }
2056
2057        let authorization_keys = request.authorization_keys();
2058
2059        let config = request.config();
2060        let transfer_config = config.transfer_config();
2061        let administrative_accounts = transfer_config.administrative_accounts();
2062
2063        let runtime_args = match request.args() {
2064            TransferRequestArgs::Raw(runtime_args) => runtime_args.clone(),
2065            TransferRequestArgs::Explicit(transfer_args) => {
2066                match RuntimeArgs::try_from(*transfer_args) {
2067                    Ok(runtime_args) => runtime_args,
2068                    Err(cve) => return TransferResult::Failure(TransferError::CLValue(cve)),
2069                }
2070            }
2071            TransferRequestArgs::Indirect(bita) => {
2072                let source_uref = match bita
2073                    .source()
2074                    .purse_uref(&mut tc.borrow_mut(), protocol_version)
2075                {
2076                    Ok(source_uref) => source_uref,
2077                    Err(tce) => return TransferResult::Failure(TransferError::TrackingCopy(tce)),
2078                };
2079                let target_uref = match bita
2080                    .target()
2081                    .purse_uref(&mut tc.borrow_mut(), protocol_version)
2082                {
2083                    Ok(target_uref) => target_uref,
2084                    Err(tce) => return TransferResult::Failure(TransferError::TrackingCopy(tce)),
2085                };
2086                let transfer_args = TransferArgs::new(
2087                    bita.to(),
2088                    source_uref,
2089                    target_uref,
2090                    bita.amount(),
2091                    bita.arg_id(),
2092                );
2093                match RuntimeArgs::try_from(transfer_args) {
2094                    Ok(runtime_args) => runtime_args,
2095                    Err(cve) => return TransferResult::Failure(TransferError::CLValue(cve)),
2096                }
2097            }
2098        };
2099
2100        let remaining_spending_limit = match runtime_args.try_get_number(ARG_AMOUNT) {
2101            Ok(amount) => amount,
2102            Err(cve) => {
2103                debug!("failed to derive remaining_spending_limit");
2104                return TransferResult::Failure(TransferError::CLValue(cve));
2105            }
2106        };
2107
2108        let mut runtime_args_builder = TransferRuntimeArgsBuilder::new(runtime_args);
2109
2110        let transfer_target_mode = match runtime_args_builder
2111            .resolve_transfer_target_mode(protocol_version, Rc::clone(&tc))
2112        {
2113            Ok(transfer_target_mode) => transfer_target_mode,
2114            Err(error) => return TransferResult::Failure(error),
2115        };
2116
2117        // On some private networks, transfers are restricted.
2118        // This means that they must either the source or target are an admin account.
2119        // This behavior is not used on public networks.
2120        if transfer_config.enforce_transfer_restrictions(&source_account_hash) {
2121            // if the source is an admin, enforce_transfer_restrictions == false
2122            // if the source is not an admin, enforce_transfer_restrictions == true,
2123            // and we must check to see if the target is an admin.
2124            // if the target is also not an admin, this transfer is not permitted.
2125            match transfer_target_mode.target_account_hash() {
2126                Some(target_account_hash) => {
2127                    let is_target_system_account =
2128                        target_account_hash == PublicKey::System.to_account_hash();
2129                    let is_target_administrator =
2130                        transfer_config.is_administrator(&target_account_hash);
2131                    if !(is_target_system_account || is_target_administrator) {
2132                        // Transferring from normal account to a purse doesn't work.
2133                        return TransferResult::Failure(TransferError::RestrictedTransferAttempted);
2134                    }
2135                }
2136                None => {
2137                    // can't allow this transfer because we are not sure if the target is an admin.
2138                    return TransferResult::Failure(TransferError::UnableToVerifyTargetIsAdmin);
2139                }
2140            }
2141        }
2142
2143        let (entity_addr, runtime_footprint, entity_access_rights) = match tc
2144            .borrow_mut()
2145            .authorized_runtime_footprint_with_access_rights(
2146                protocol_version,
2147                source_account_hash,
2148                authorization_keys,
2149                &administrative_accounts,
2150            ) {
2151            Ok(ret) => ret,
2152            Err(tce) => {
2153                return TransferResult::Failure(TransferError::TrackingCopy(tce));
2154            }
2155        };
2156        let entity_key = if config.enable_addressable_entity() {
2157            Key::AddressableEntity(entity_addr)
2158        } else {
2159            match entity_addr {
2160                EntityAddr::System(hash) | EntityAddr::SmartContract(hash) => Key::Hash(hash),
2161                EntityAddr::Account(hash) => Key::Account(AccountHash::new(hash)),
2162            }
2163        };
2164        let id = Id::Transaction(request.transaction_hash());
2165        let phase = Phase::Session;
2166        let address_generator = AddressGenerator::new(&id.seed(), phase);
2167        // IMPORTANT: this runtime _must_ use the payer's context.
2168        let mut runtime = RuntimeNative::new(
2169            config.clone(),
2170            protocol_version,
2171            id,
2172            Arc::new(RwLock::new(address_generator)),
2173            Rc::clone(&tc),
2174            source_account_hash,
2175            entity_key,
2176            runtime_footprint.clone(),
2177            entity_access_rights,
2178            remaining_spending_limit,
2179            phase,
2180        );
2181
2182        match transfer_target_mode {
2183            TransferTargetMode::ExistingAccount { .. } | TransferTargetMode::PurseExists { .. } => {
2184                // Noop
2185            }
2186            TransferTargetMode::CreateAccount(account_hash) => {
2187                let main_purse = match runtime.mint(U512::zero()) {
2188                    Ok(uref) => uref,
2189                    Err(mint_error) => {
2190                        return TransferResult::Failure(TransferError::Mint(mint_error));
2191                    }
2192                };
2193
2194                let account = Account::create(account_hash, NamedKeys::new(), main_purse);
2195                if let Err(tce) = tc
2196                    .borrow_mut()
2197                    .create_addressable_entity_from_account(account, protocol_version)
2198                {
2199                    return TransferResult::Failure(tce.into());
2200                }
2201            }
2202        }
2203        let transfer_args = match runtime_args_builder.build(
2204            &runtime_footprint,
2205            protocol_version,
2206            Rc::clone(&tc),
2207        ) {
2208            Ok(transfer_args) => transfer_args,
2209            Err(error) => return TransferResult::Failure(error),
2210        };
2211        if let Err(mint_error) = runtime.transfer(
2212            transfer_args.to(),
2213            transfer_args.source(),
2214            transfer_args.target(),
2215            transfer_args.amount(),
2216            transfer_args.arg_id(),
2217        ) {
2218            return TransferResult::Failure(TransferError::Mint(mint_error));
2219        }
2220
2221        let transfers = runtime.into_transfers();
2222
2223        let effects = tc.borrow_mut().effects();
2224        let cache = tc.borrow_mut().cache();
2225
2226        TransferResult::Success {
2227            transfers,
2228            effects,
2229            cache,
2230        }
2231    }
2232
2233    /// Direct burn.
2234    fn burn(&self, request: BurnRequest) -> BurnResult {
2235        let state_hash = request.state_hash();
2236        let tc = match self.tracking_copy(state_hash) {
2237            Ok(Some(tc)) => Rc::new(RefCell::new(tc)),
2238            Ok(None) => return BurnResult::RootNotFound,
2239            Err(err) => {
2240                return BurnResult::Failure(BurnError::TrackingCopy(TrackingCopyError::Storage(
2241                    err,
2242                )));
2243            }
2244        };
2245
2246        let source_account_hash = request.initiator().account_hash();
2247        let protocol_version = request.protocol_version();
2248        if let Err(tce) = tc
2249            .borrow_mut()
2250            .migrate_account(source_account_hash, protocol_version)
2251        {
2252            return BurnResult::Failure(tce.into());
2253        }
2254
2255        let authorization_keys = request.authorization_keys();
2256
2257        let config = request.config();
2258
2259        let runtime_args = match request.args() {
2260            BurnRequestArgs::Raw(runtime_args) => runtime_args.clone(),
2261            BurnRequestArgs::Explicit(transfer_args) => {
2262                match RuntimeArgs::try_from(*transfer_args) {
2263                    Ok(runtime_args) => runtime_args,
2264                    Err(cve) => return BurnResult::Failure(BurnError::CLValue(cve)),
2265                }
2266            }
2267        };
2268
2269        let runtime_args_builder = BurnRuntimeArgsBuilder::new(runtime_args);
2270
2271        let (entity_addr, mut footprint, mut entity_access_rights) = match tc
2272            .borrow_mut()
2273            .authorized_runtime_footprint_with_access_rights(
2274                protocol_version,
2275                source_account_hash,
2276                authorization_keys,
2277                &BTreeSet::default(),
2278            ) {
2279            Ok(ret) => ret,
2280            Err(tce) => {
2281                return BurnResult::Failure(BurnError::TrackingCopy(tce));
2282            }
2283        };
2284        let entity_key = if config.enable_addressable_entity() {
2285            Key::AddressableEntity(entity_addr)
2286        } else {
2287            match entity_addr {
2288                EntityAddr::System(hash) | EntityAddr::SmartContract(hash) => Key::Hash(hash),
2289                EntityAddr::Account(hash) => Key::Account(AccountHash::new(hash)),
2290            }
2291        };
2292
2293        // extend named keys with total supply
2294        match tc
2295            .borrow_mut()
2296            .system_contract_named_key(MINT, TOTAL_SUPPLY_KEY)
2297        {
2298            Ok(Some(k)) => {
2299                match k.as_uref() {
2300                    Some(uref) => entity_access_rights.extend(&[*uref]),
2301                    None => {
2302                        return BurnResult::Failure(BurnError::TrackingCopy(
2303                            TrackingCopyError::UnexpectedKeyVariant(k),
2304                        ));
2305                    }
2306                }
2307                footprint.insert_into_named_keys(TOTAL_SUPPLY_KEY.into(), k);
2308            }
2309            Ok(None) => {
2310                return BurnResult::Failure(BurnError::TrackingCopy(
2311                    TrackingCopyError::NamedKeyNotFound(TOTAL_SUPPLY_KEY.into()),
2312                ));
2313            }
2314            Err(tce) => {
2315                return BurnResult::Failure(BurnError::TrackingCopy(tce));
2316            }
2317        };
2318        let id = Id::Transaction(request.transaction_hash());
2319        let phase = Phase::Session;
2320        let address_generator = AddressGenerator::new(&id.seed(), phase);
2321        let burn_args = match runtime_args_builder.build(&footprint, Rc::clone(&tc)) {
2322            Ok(burn_args) => burn_args,
2323            Err(error) => return BurnResult::Failure(error),
2324        };
2325
2326        // IMPORTANT: this runtime _must_ use the payer's context.
2327        let mut runtime = RuntimeNative::new(
2328            config.clone(),
2329            protocol_version,
2330            id,
2331            Arc::new(RwLock::new(address_generator)),
2332            Rc::clone(&tc),
2333            source_account_hash,
2334            entity_key,
2335            footprint.clone(),
2336            entity_access_rights,
2337            burn_args.amount(),
2338            phase,
2339        );
2340
2341        if let Err(mint_error) = runtime.burn(burn_args.source(), burn_args.amount()) {
2342            return BurnResult::Failure(BurnError::Mint(mint_error));
2343        }
2344
2345        let effects = tc.borrow_mut().effects();
2346        let cache = tc.borrow_mut().cache();
2347
2348        BurnResult::Success { effects, cache }
2349    }
2350
2351    /// Gets all values under a given key tag.
2352    fn tagged_values(&self, request: TaggedValuesRequest) -> TaggedValuesResult {
2353        let state_hash = request.state_hash();
2354        let mut tc = match self.tracking_copy(state_hash) {
2355            Ok(Some(tc)) => tc,
2356            Ok(None) => return TaggedValuesResult::RootNotFound,
2357            Err(gse) => return TaggedValuesResult::Failure(TrackingCopyError::Storage(gse)),
2358        };
2359
2360        let key_tag = request.key_tag();
2361        let keys = match tc.get_keys(&key_tag) {
2362            Ok(keys) => keys,
2363            Err(tce) => return TaggedValuesResult::Failure(tce),
2364        };
2365
2366        let mut values = vec![];
2367        for key in keys {
2368            match tc.get(&key) {
2369                Ok(Some(value)) => {
2370                    values.push(value);
2371                }
2372                Ok(None) => {}
2373                Err(error) => return TaggedValuesResult::Failure(error),
2374            }
2375        }
2376
2377        TaggedValuesResult::Success {
2378            values,
2379            selection: request.selection(),
2380        }
2381    }
2382
2383    /// Gets all values under a given key prefix.
2384    /// Currently, this ignores the cache and only provides values from the trie.
2385    fn prefixed_values(&self, request: PrefixedValuesRequest) -> PrefixedValuesResult {
2386        let mut tc = match self.tracking_copy(request.state_hash()) {
2387            Ok(Some(tc)) => tc,
2388            Ok(None) => return PrefixedValuesResult::RootNotFound,
2389            Err(err) => return PrefixedValuesResult::Failure(TrackingCopyError::Storage(err)),
2390        };
2391        match tc.get_keys_by_prefix(request.key_prefix()) {
2392            Ok(keys) => {
2393                let mut values = Vec::with_capacity(keys.len());
2394                for key in keys {
2395                    match tc.get(&key) {
2396                        Ok(Some(value)) => values.push(value),
2397                        Ok(None) => {}
2398                        Err(error) => return PrefixedValuesResult::Failure(error),
2399                    }
2400                }
2401                PrefixedValuesResult::Success {
2402                    values,
2403                    key_prefix: request.key_prefix().clone(),
2404                }
2405            }
2406            Err(error) => PrefixedValuesResult::Failure(error),
2407        }
2408    }
2409
2410    /// Reads a `Trie` from the state if it is present
2411    fn trie(&self, request: TrieRequest) -> TrieResult;
2412
2413    /// Persists a trie element.
2414    fn put_trie(&self, request: PutTrieRequest) -> PutTrieResult;
2415
2416    /// Finds all the children of `trie_raw` which aren't present in the state.
2417    fn missing_children(&self, trie_raw: &[u8]) -> Result<Vec<Digest>, GlobalStateError>;
2418
2419    /// Gets the value of enable entity flag.
2420    fn enable_entity(&self) -> bool;
2421}
2422
2423fn get_round_seigniorage_rate_data<T: StateProvider>(
2424    state_provider: &T,
2425    scr: &SystemHashRegistry,
2426    state_hash: Digest,
2427    enable_addressable_entity: bool,
2428) -> RoundSeigniorageRateResult {
2429    let query_request = match scr.get(MINT).copied() {
2430        Some(mint_hash) => {
2431            let key = if !enable_addressable_entity {
2432                Key::Hash(mint_hash)
2433            } else {
2434                Key::AddressableEntity(EntityAddr::System(mint_hash))
2435            };
2436            QueryRequest::new(
2437                state_hash,
2438                key,
2439                vec![ROUND_SEIGNIORAGE_RATE_KEY.to_string()],
2440            )
2441        }
2442        None => {
2443            error!("unexpected query failure; mint not found");
2444            return RoundSeigniorageRateResult::MintNotFound;
2445        }
2446    };
2447
2448    match state_provider.query(query_request) {
2449        QueryResult::RootNotFound => RoundSeigniorageRateResult::RootNotFound,
2450        QueryResult::ValueNotFound(msg) => RoundSeigniorageRateResult::ValueNotFound(msg),
2451        QueryResult::Failure(tce) => RoundSeigniorageRateResult::Failure(tce),
2452        QueryResult::Success { value, proofs: _ } => {
2453            let cl_value = match value.into_cl_value() {
2454                Some(cl_value) => cl_value,
2455                None => {
2456                    error!("unexpected query failure; total supply is not a CLValue");
2457                    return RoundSeigniorageRateResult::Failure(
2458                        TrackingCopyError::UnexpectedStoredValueVariant,
2459                    );
2460                }
2461            };
2462
2463            match cl_value.into_t() {
2464                Ok(rate) => RoundSeigniorageRateResult::Success { rate },
2465                Err(cve) => RoundSeigniorageRateResult::Failure(TrackingCopyError::CLValue(cve)),
2466            }
2467        }
2468    }
2469}
2470
2471fn get_total_supply_data<T: StateProvider>(
2472    state_provider: &T,
2473    scr: &SystemHashRegistry,
2474    state_hash: Digest,
2475    enable_addressable_entity: bool,
2476) -> TotalSupplyResult {
2477    let query_request = match scr.get(MINT).copied() {
2478        Some(mint_hash) => {
2479            let key = if !enable_addressable_entity {
2480                Key::Hash(mint_hash)
2481            } else {
2482                Key::AddressableEntity(EntityAddr::System(mint_hash))
2483            };
2484            QueryRequest::new(state_hash, key, vec![TOTAL_SUPPLY_KEY.to_string()])
2485        }
2486        None => {
2487            error!("unexpected query failure; mint not found");
2488            return TotalSupplyResult::MintNotFound;
2489        }
2490    };
2491    match state_provider.query(query_request) {
2492        QueryResult::RootNotFound => TotalSupplyResult::RootNotFound,
2493        QueryResult::ValueNotFound(msg) => TotalSupplyResult::ValueNotFound(msg),
2494        QueryResult::Failure(tce) => TotalSupplyResult::Failure(tce),
2495        QueryResult::Success { value, proofs: _ } => {
2496            let cl_value = match value.into_cl_value() {
2497                Some(cl_value) => cl_value,
2498                None => {
2499                    error!("unexpected query failure; total supply is not a CLValue");
2500                    return TotalSupplyResult::Failure(
2501                        TrackingCopyError::UnexpectedStoredValueVariant,
2502                    );
2503                }
2504            };
2505
2506            match cl_value.into_t() {
2507                Ok(total_supply) => TotalSupplyResult::Success { total_supply },
2508                Err(cve) => TotalSupplyResult::Failure(TrackingCopyError::CLValue(cve)),
2509            }
2510        }
2511    }
2512}
2513
2514fn get_snapshot_data<T: StateProvider>(
2515    state_provider: &T,
2516    scr: &SystemHashRegistry,
2517    state_hash: Digest,
2518    enable_addressable_entity: bool,
2519) -> SeigniorageRecipientsResult {
2520    let (snapshot_query_request, snapshot_version_query_request) =
2521        match build_query_requests(scr, state_hash, enable_addressable_entity) {
2522            Ok(res) => res,
2523            Err(res) => return res,
2524        };
2525
2526    // check if snapshot version flag is present
2527    let snapshot_version: Option<u8> =
2528        match query_snapshot_version(state_provider, snapshot_version_query_request) {
2529            Ok(value) => value,
2530            Err(value) => return value,
2531        };
2532
2533    let snapshot = match query_snapshot(state_provider, snapshot_version, snapshot_query_request) {
2534        Ok(snapshot) => snapshot,
2535        Err(value) => return value,
2536    };
2537
2538    SeigniorageRecipientsResult::Success {
2539        seigniorage_recipients: snapshot,
2540    }
2541}
2542
2543fn query_snapshot<T: StateProvider>(
2544    state_provider: &T,
2545    snapshot_version: Option<u8>,
2546    snapshot_query_request: QueryRequest,
2547) -> Result<SeigniorageRecipientsSnapshot, SeigniorageRecipientsResult> {
2548    match state_provider.query(snapshot_query_request) {
2549        QueryResult::RootNotFound => Err(SeigniorageRecipientsResult::RootNotFound),
2550        QueryResult::Failure(error) => {
2551            error!(?error, "unexpected tracking copy error");
2552            Err(SeigniorageRecipientsResult::Failure(error))
2553        }
2554        QueryResult::ValueNotFound(msg) => {
2555            error!(%msg, "value not found");
2556            Err(SeigniorageRecipientsResult::ValueNotFound(msg))
2557        }
2558        QueryResult::Success { value, proofs: _ } => {
2559            let cl_value = match value.into_cl_value() {
2560                Some(snapshot_cl_value) => snapshot_cl_value,
2561                None => {
2562                    error!("unexpected query failure; seigniorage recipients snapshot is not a CLValue");
2563                    return Err(SeigniorageRecipientsResult::Failure(
2564                        TrackingCopyError::UnexpectedStoredValueVariant,
2565                    ));
2566                }
2567            };
2568
2569            match snapshot_version {
2570                Some(_) => {
2571                    let snapshot = match cl_value.into_t() {
2572                        Ok(snapshot) => snapshot,
2573                        Err(cve) => {
2574                            error!("Failed to convert snapshot from CLValue");
2575                            return Err(SeigniorageRecipientsResult::Failure(
2576                                TrackingCopyError::CLValue(cve),
2577                            ));
2578                        }
2579                    };
2580                    Ok(SeigniorageRecipientsSnapshot::V2(snapshot))
2581                }
2582                None => {
2583                    let snapshot = match cl_value.into_t() {
2584                        Ok(snapshot) => snapshot,
2585                        Err(cve) => {
2586                            error!("Failed to convert snapshot from CLValue");
2587                            return Err(SeigniorageRecipientsResult::Failure(
2588                                TrackingCopyError::CLValue(cve),
2589                            ));
2590                        }
2591                    };
2592                    Ok(SeigniorageRecipientsSnapshot::V1(snapshot))
2593                }
2594            }
2595        }
2596    }
2597}
2598
2599fn query_snapshot_version<T: StateProvider>(
2600    state_provider: &T,
2601    snapshot_version_query_request: QueryRequest,
2602) -> Result<Option<u8>, SeigniorageRecipientsResult> {
2603    match state_provider.query(snapshot_version_query_request) {
2604        QueryResult::RootNotFound => Err(SeigniorageRecipientsResult::RootNotFound),
2605        QueryResult::Failure(error) => {
2606            error!(?error, "unexpected tracking copy error");
2607            Err(SeigniorageRecipientsResult::Failure(error))
2608        }
2609        QueryResult::ValueNotFound(_msg) => Ok(None),
2610        QueryResult::Success { value, proofs: _ } => {
2611            let cl_value = match value.into_cl_value() {
2612                Some(snapshot_version_cl_value) => snapshot_version_cl_value,
2613                None => {
2614                    error!("unexpected query failure; seigniorage recipients snapshot version is not a CLValue");
2615                    return Err(SeigniorageRecipientsResult::Failure(
2616                        TrackingCopyError::UnexpectedStoredValueVariant,
2617                    ));
2618                }
2619            };
2620            match cl_value.into_t() {
2621                Ok(snapshot_version) => Ok(Some(snapshot_version)),
2622                Err(cve) => Err(SeigniorageRecipientsResult::Failure(
2623                    TrackingCopyError::CLValue(cve),
2624                )),
2625            }
2626        }
2627    }
2628}
2629
2630fn build_query_requests(
2631    scr: &SystemHashRegistry,
2632    state_hash: Digest,
2633    enable_addressable_entity: bool,
2634) -> Result<(QueryRequest, QueryRequest), SeigniorageRecipientsResult> {
2635    match scr.get(AUCTION).copied() {
2636        Some(auction_hash) => {
2637            let key = if !enable_addressable_entity {
2638                Key::Hash(auction_hash)
2639            } else {
2640                Key::AddressableEntity(EntityAddr::System(auction_hash))
2641            };
2642            Ok((
2643                QueryRequest::new(
2644                    state_hash,
2645                    key,
2646                    vec![SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY.to_string()],
2647                ),
2648                QueryRequest::new(
2649                    state_hash,
2650                    key,
2651                    vec![SEIGNIORAGE_RECIPIENTS_SNAPSHOT_VERSION_KEY.to_string()],
2652                ),
2653            ))
2654        }
2655        None => Err(SeigniorageRecipientsResult::AuctionNotFound),
2656    }
2657}
2658
2659/// Write multiple key/stored value pairs to the store in a single rw transaction.
2660pub fn put_stored_values<'a, R, S, E>(
2661    environment: &'a R,
2662    store: &S,
2663    prestate_hash: Digest,
2664    stored_values: Vec<(Key, StoredValue)>,
2665) -> Result<Digest, E>
2666where
2667    R: TransactionSource<'a, Handle = S::Handle>,
2668    S: TrieStore<Key, StoredValue>,
2669    S::Error: From<R::Error>,
2670    E: From<R::Error>
2671        + From<S::Error>
2672        + From<bytesrepr::Error>
2673        + From<CommitError>
2674        + From<TrieStoreCacheError>,
2675{
2676    let mut txn = environment.create_read_write_txn()?;
2677    let state_root = prestate_hash;
2678    let maybe_root: Option<Trie<Key, StoredValue>> = store.get(&txn, &state_root)?;
2679    if maybe_root.is_none() {
2680        return Err(CommitError::RootNotFound(prestate_hash).into());
2681    };
2682
2683    let state_root =
2684        batch_write::<_, _, _, _, _, E>(&mut txn, store, &state_root, stored_values.into_iter())?;
2685    txn.commit()?;
2686    Ok(state_root)
2687}
2688
2689/// Commit `effects` to the store.
2690pub fn commit<'a, R, S, E>(
2691    environment: &'a R,
2692    store: &S,
2693    prestate_hash: Digest,
2694    effects: Effects,
2695) -> Result<Digest, E>
2696where
2697    R: TransactionSource<'a, Handle = S::Handle>,
2698    S: TrieStore<Key, StoredValue>,
2699    S::Error: From<R::Error>,
2700    E: From<R::Error>
2701        + From<S::Error>
2702        + From<bytesrepr::Error>
2703        + From<CommitError>
2704        + From<GlobalStateError>, /* even tho E is currently always GSE, this is required to
2705                                   * satisfy the compiler */
2706{
2707    let mut txn = environment.create_read_write_txn()?;
2708    let mut state_root = prestate_hash;
2709
2710    let maybe_root: Option<Trie<Key, StoredValue>> = store.get(&txn, &state_root)?;
2711
2712    if maybe_root.is_none() {
2713        return Err(CommitError::RootNotFound(prestate_hash).into());
2714    };
2715
2716    for (key, kind) in effects.value().into_iter().map(TransformV2::destructure) {
2717        let read_result = read::<_, _, _, _, E>(&txn, store, &state_root, &key)?;
2718
2719        let instruction = match (read_result, kind) {
2720            (_, TransformKindV2::Identity) => {
2721                // effectively a noop.
2722                continue;
2723            }
2724            (ReadResult::NotFound, TransformKindV2::Write(new_value)) => {
2725                TransformInstruction::store(new_value)
2726            }
2727            (ReadResult::NotFound, TransformKindV2::Prune(key)) => {
2728                // effectively a noop.
2729                debug!(
2730                    ?state_root,
2731                    ?key,
2732                    "commit: attempt to prune nonexistent record; this may happen if a key is both added and pruned in the same commit."
2733                );
2734                continue;
2735            }
2736            (ReadResult::NotFound, transform_kind) => {
2737                error!(
2738                    ?state_root,
2739                    ?key,
2740                    ?transform_kind,
2741                    "commit: key not found while attempting to apply transform"
2742                );
2743                return Err(CommitError::KeyNotFound(key).into());
2744            }
2745            (ReadResult::Found(current_value), transform_kind) => {
2746                match transform_kind.apply(current_value) {
2747                    Ok(instruction) => instruction,
2748                    Err(err) => {
2749                        error!(
2750                            ?state_root,
2751                            ?key,
2752                            ?err,
2753                            "commit: key found, but could not apply transform"
2754                        );
2755                        return Err(CommitError::TransformError(err).into());
2756                    }
2757                }
2758            }
2759            (ReadResult::RootNotFound, transform_kind) => {
2760                error!(
2761                    ?state_root,
2762                    ?key,
2763                    ?transform_kind,
2764                    "commit: failed to read state root while processing transform"
2765                );
2766                return Err(CommitError::ReadRootNotFound(state_root).into());
2767            }
2768        };
2769
2770        match instruction {
2771            TransformInstruction::Store(value) => {
2772                let write_result =
2773                    write::<_, _, _, _, E>(&mut txn, store, &state_root, &key, &value)?;
2774
2775                match write_result {
2776                    WriteResult::Written(root_hash) => {
2777                        state_root = root_hash;
2778                    }
2779                    WriteResult::AlreadyExists => (),
2780                    WriteResult::RootNotFound => {
2781                        error!(?state_root, ?key, ?value, "commit: root not found");
2782                        return Err(CommitError::WriteRootNotFound(state_root).into());
2783                    }
2784                }
2785            }
2786            TransformInstruction::Prune(key) => {
2787                let prune_result = prune::<_, _, _, _, E>(&mut txn, store, &state_root, &key)?;
2788
2789                match prune_result {
2790                    TriePruneResult::Pruned(root_hash) => {
2791                        state_root = root_hash;
2792                    }
2793                    TriePruneResult::MissingKey => {
2794                        warn!("commit: pruning attempt failed for {}", key);
2795                    }
2796                    TriePruneResult::RootNotFound => {
2797                        error!(?state_root, ?key, "commit: root not found");
2798                        return Err(CommitError::WriteRootNotFound(state_root).into());
2799                    }
2800                    TriePruneResult::Failure(gse) => {
2801                        return Err(gse.into()); // currently this is always reflexive
2802                    }
2803                }
2804            }
2805        }
2806    }
2807
2808    txn.commit()?;
2809
2810    Ok(state_root)
2811}