iota_config/
certificate_deny_config.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::collections::HashSet;
6
7use iota_types::base_types::TransactionDigest;
8use once_cell::sync::OnceCell;
9use serde::{Deserialize, Serialize};
10
11#[derive(Clone, Debug, Default, Deserialize, Serialize)]
12#[serde(rename_all = "kebab-case")]
13pub struct CertificateDenyConfig {
14    /// A list of certificate digests that are known to be either
15    /// deterministically crashing every validator, or causing every
16    /// validator to hang forever, i.e. there is no way for such transaction
17    /// to execute successfully today. Now with this config, a validator
18    /// will decide that this transaction will always yield ExecutionError
19    /// and charge gas accordingly. This config is meant for a fast
20    /// temporary fix for a known issue, and should be removed
21    /// once the issue is fixed. However, since a certificate once executed will
22    /// be included in checkpoints, all future executions of this
23    /// transaction through replay must also lead to the same result (i.e.
24    /// ExecutionError). So when we remove this config, we need to make sure
25    /// it's added to the constant certificate deny list in the Rust code (TODO:
26    /// code link).
27    #[serde(default, skip_serializing_if = "Vec::is_empty")]
28    certificate_deny_list: Vec<TransactionDigest>,
29
30    /// In-memory cache for faster lookup of the certificate deny list.
31    #[serde(skip)]
32    certificate_deny_set: OnceCell<HashSet<TransactionDigest>>,
33}
34
35impl CertificateDenyConfig {
36    pub fn new() -> Self {
37        Self::default()
38    }
39
40    pub fn certificate_deny_set(&self) -> &HashSet<TransactionDigest> {
41        self.certificate_deny_set.get_or_init(|| {
42            self.certificate_deny_list
43                .iter()
44                .cloned()
45                .collect::<HashSet<_>>()
46        })
47    }
48}
49
50#[derive(Default)]
51pub struct CertificateDenyConfigBuilder {
52    config: CertificateDenyConfig,
53}
54
55impl CertificateDenyConfigBuilder {
56    pub fn new() -> Self {
57        Self::default()
58    }
59
60    pub fn build(self) -> CertificateDenyConfig {
61        self.config
62    }
63
64    pub fn add_certificate_deny(mut self, certificate: TransactionDigest) -> Self {
65        self.config.certificate_deny_list.push(certificate);
66        self
67    }
68}