Skip to content

Commit 793563f

Browse files
authored
jwk #1: validator txn for publishing updates (aptos-labs#11853)
* jwk types update * update * update * jwk txn and execution * update * fix dummy * update * update * update * update * update * update * remove dummy txns * check voting power than verify signature * fix warnings * update * update QuorumCertifiedUpdate struct
1 parent ea91067 commit 793563f

File tree

25 files changed

+549
-172
lines changed

25 files changed

+549
-172
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aptos-move/aptos-vm/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ rust-version = { workspace = true }
1515
[dependencies]
1616
anyhow = { workspace = true }
1717
aptos-aggregator = { workspace = true }
18+
aptos-bitvec = { workspace = true }
1819
aptos-block-executor = { workspace = true }
1920
aptos-block-partitioner = { workspace = true }
2021
aptos-crypto = { workspace = true }
@@ -65,13 +66,13 @@ tracing = { workspace = true }
6566
[dev-dependencies]
6667
aptos-aggregator = { workspace = true, features = ["testing"] }
6768
aptos-language-e2e-tests = { workspace = true }
68-
aptos-types = { workspace = true }
69+
aptos-types = { workspace = true, features = ["fuzzing"] }
6970
claims = { workspace = true }
7071
proptest = { workspace = true }
7172
rand_core = { workspace = true }
7273

7374
[features]
7475
default = []
75-
fuzzing = ["move-core-types/fuzzing", "move-binary-format/fuzzing", "move-vm-types/fuzzing", "aptos-framework/fuzzing"]
76+
fuzzing = ["move-core-types/fuzzing", "move-binary-format/fuzzing", "move-vm-types/fuzzing", "aptos-framework/fuzzing", "aptos-types/fuzzing"]
7677
failpoints = ["fail/failpoints", "move-vm-runtime/failpoints"]
7778
testing = ["move-unit-test", "aptos-framework/testing"]

aptos-move/aptos-vm/src/system_module_names.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ pub static RECONFIGURATION_WITH_DKG_MODULE: Lazy<ModuleId> = Lazy::new(|| {
3939

4040
pub const FINISH_WITH_DKG_RESULT: &IdentStr = ident_str!("finish_with_dkg_result");
4141

42+
pub static JWKS_MODULE: Lazy<ModuleId> = Lazy::new(|| {
43+
ModuleId::new(
44+
account_config::CORE_CODE_ADDRESS,
45+
ident_str!("jwks").to_owned(),
46+
)
47+
});
48+
49+
pub const UPSERT_INTO_OBSERVED_JWKS: &IdentStr = ident_str!("upsert_into_observed_jwks");
50+
4251
pub static MULTISIG_ACCOUNT_MODULE: Lazy<ModuleId> = Lazy::new(|| {
4352
ModuleId::new(
4453
account_config::CORE_CODE_ADDRESS,

aptos-move/aptos-vm/src/validator_txns/dummy.rs

Lines changed: 0 additions & 38 deletions
This file was deleted.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// Copyright © Aptos Foundation
2+
3+
use crate::{
4+
aptos_vm::get_or_vm_startup_failure,
5+
errors::expect_only_successful_execution,
6+
move_vm_ext::{AptosMoveResolver, SessionId},
7+
system_module_names::{JWKS_MODULE, UPSERT_INTO_OBSERVED_JWKS},
8+
validator_txns::jwk::{
9+
ExecutionFailure::{Expected, Unexpected},
10+
ExpectedFailure::{
11+
IncorrectVersion, MissingResourceObservedJWKs, MissingResourceValidatorSet,
12+
MultiSigVerificationFailed, NotEnoughVotingPower,
13+
},
14+
},
15+
AptosVM,
16+
};
17+
use aptos_types::{
18+
fee_statement::FeeStatement,
19+
jwks,
20+
jwks::{Issuer, ObservedJWKs, ProviderJWKs, QuorumCertifiedUpdate},
21+
move_utils::as_move_value::AsMoveValue,
22+
on_chain_config::{OnChainConfig, ValidatorSet},
23+
transaction::{ExecutionStatus, TransactionStatus},
24+
validator_verifier::ValidatorVerifier,
25+
};
26+
use aptos_vm_logging::log_schema::AdapterLogSchema;
27+
use aptos_vm_types::output::VMOutput;
28+
use move_core_types::{
29+
account_address::AccountAddress,
30+
value::{serialize_values, MoveValue},
31+
vm_status::{AbortLocation, StatusCode, VMStatus},
32+
};
33+
use move_vm_types::gas::UnmeteredGasMeter;
34+
use std::collections::HashMap;
35+
36+
enum ExpectedFailure {
37+
// Move equivalent: `errors::invalid_argument(*)`
38+
IncorrectVersion = 0x010103,
39+
MultiSigVerificationFailed = 0x010104,
40+
NotEnoughVotingPower = 0x010105,
41+
42+
// Move equivalent: `errors::invalid_state(*)`
43+
MissingResourceValidatorSet = 0x30101,
44+
MissingResourceObservedJWKs = 0x30102,
45+
}
46+
47+
enum ExecutionFailure {
48+
Expected(ExpectedFailure),
49+
Unexpected(VMStatus),
50+
}
51+
52+
impl AptosVM {
53+
pub(crate) fn process_jwk_update(
54+
&self,
55+
resolver: &impl AptosMoveResolver,
56+
log_context: &AdapterLogSchema,
57+
session_id: SessionId,
58+
update: jwks::QuorumCertifiedUpdate,
59+
) -> Result<(VMStatus, VMOutput), VMStatus> {
60+
match self.process_jwk_update_inner(resolver, log_context, session_id, update) {
61+
Ok((vm_status, vm_output)) => Ok((vm_status, vm_output)),
62+
Err(Expected(failure)) => {
63+
// Pretend we are inside Move, and expected failures are like Move aborts.
64+
Ok((
65+
VMStatus::MoveAbort(AbortLocation::Script, failure as u64),
66+
VMOutput::empty_with_status(TransactionStatus::Discard(StatusCode::ABORTED)),
67+
))
68+
},
69+
Err(Unexpected(vm_status)) => Err(vm_status),
70+
}
71+
}
72+
73+
fn process_jwk_update_inner(
74+
&self,
75+
resolver: &impl AptosMoveResolver,
76+
log_context: &AdapterLogSchema,
77+
session_id: SessionId,
78+
update: jwks::QuorumCertifiedUpdate,
79+
) -> Result<(VMStatus, VMOutput), ExecutionFailure> {
80+
// Load resources.
81+
let validator_set = ValidatorSet::fetch_config(resolver)
82+
.ok_or_else(|| Expected(MissingResourceValidatorSet))?;
83+
let observed_jwks = ObservedJWKs::fetch_config(resolver)
84+
.ok_or_else(|| Expected(MissingResourceObservedJWKs))?;
85+
86+
let mut jwks_by_issuer: HashMap<Issuer, ProviderJWKs> =
87+
observed_jwks.into_providers_jwks().into();
88+
let issuer = update.update.issuer.clone();
89+
let on_chain = jwks_by_issuer
90+
.entry(issuer.clone())
91+
.or_insert_with(|| ProviderJWKs::new(issuer));
92+
let verifier = ValidatorVerifier::from(&validator_set);
93+
94+
let QuorumCertifiedUpdate {
95+
update: observed,
96+
multi_sig,
97+
} = update;
98+
99+
// Check version.
100+
if on_chain.version + 1 != observed.version {
101+
return Err(Expected(IncorrectVersion));
102+
}
103+
104+
let authors = multi_sig.get_signers_addresses(&verifier.get_ordered_account_addresses());
105+
106+
// Check voting power.
107+
verifier
108+
.check_voting_power(authors.iter(), true)
109+
.map_err(|_| Expected(NotEnoughVotingPower))?;
110+
111+
// Verify multi-sig.
112+
verifier
113+
.verify_multi_signatures(&observed, &multi_sig)
114+
.map_err(|_| Expected(MultiSigVerificationFailed))?;
115+
116+
// All verification passed. Apply the `observed`.
117+
let mut gas_meter = UnmeteredGasMeter;
118+
let mut session = self.new_session(resolver, session_id);
119+
let args = vec![
120+
MoveValue::Signer(AccountAddress::ONE),
121+
vec![observed].as_move_value(),
122+
];
123+
124+
session
125+
.execute_function_bypass_visibility(
126+
&JWKS_MODULE,
127+
UPSERT_INTO_OBSERVED_JWKS,
128+
vec![],
129+
serialize_values(&args),
130+
&mut gas_meter,
131+
)
132+
.map_err(|e| {
133+
expect_only_successful_execution(e, UPSERT_INTO_OBSERVED_JWKS.as_str(), log_context)
134+
})
135+
.map_err(|r| Unexpected(r.unwrap_err()))?;
136+
137+
let output = crate::aptos_vm::get_transaction_output(
138+
session,
139+
FeeStatement::zero(),
140+
ExecutionStatus::Success,
141+
&get_or_vm_startup_failure(&self.storage_gas_params, log_context)
142+
.map_err(Unexpected)?
143+
.change_set_configs,
144+
)
145+
.map_err(Unexpected)?;
146+
147+
Ok((VMStatus::Executed, output))
148+
}
149+
}

aptos-move/aptos-vm/src/validator_txns/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ impl AptosVM {
2121
ValidatorTransaction::DKGResult(dkg_node) => {
2222
self.process_dkg_result(resolver, log_context, session_id, dkg_node)
2323
},
24-
ValidatorTransaction::DummyTopic1(dummy) | ValidatorTransaction::DummyTopic2(dummy) => {
25-
self.process_dummy_validator_txn(resolver, log_context, session_id, dummy)
24+
ValidatorTransaction::ObservedJWKUpdate(jwk_update) => {
25+
self.process_jwk_update(resolver, log_context, session_id, jwk_update)
2626
},
2727
}
2828
}
2929
}
3030

3131
mod dkg;
32-
mod dummy;
32+
mod jwk;

aptos-move/framework/aptos-framework/doc/jwks.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,51 @@ This is what applications should consume.
620620

621621

622622

623+
<a id="0x1_jwks_ENATIVE_INCORRECT_VERSION"></a>
624+
625+
626+
627+
<pre><code><b>const</b> <a href="jwks.md#0x1_jwks_ENATIVE_INCORRECT_VERSION">ENATIVE_INCORRECT_VERSION</a>: u64 = 259;
628+
</code></pre>
629+
630+
631+
632+
<a id="0x1_jwks_ENATIVE_MISSING_RESOURCE_OBSERVED_JWKS"></a>
633+
634+
635+
636+
<pre><code><b>const</b> <a href="jwks.md#0x1_jwks_ENATIVE_MISSING_RESOURCE_OBSERVED_JWKS">ENATIVE_MISSING_RESOURCE_OBSERVED_JWKS</a>: u64 = 258;
637+
</code></pre>
638+
639+
640+
641+
<a id="0x1_jwks_ENATIVE_MISSING_RESOURCE_VALIDATOR_SET"></a>
642+
643+
644+
645+
<pre><code><b>const</b> <a href="jwks.md#0x1_jwks_ENATIVE_MISSING_RESOURCE_VALIDATOR_SET">ENATIVE_MISSING_RESOURCE_VALIDATOR_SET</a>: u64 = 257;
646+
</code></pre>
647+
648+
649+
650+
<a id="0x1_jwks_ENATIVE_MULTISIG_VERIFICATION_FAILED"></a>
651+
652+
653+
654+
<pre><code><b>const</b> <a href="jwks.md#0x1_jwks_ENATIVE_MULTISIG_VERIFICATION_FAILED">ENATIVE_MULTISIG_VERIFICATION_FAILED</a>: u64 = 260;
655+
</code></pre>
656+
657+
658+
659+
<a id="0x1_jwks_ENATIVE_NOT_ENOUGH_VOTING_POWER"></a>
660+
661+
662+
663+
<pre><code><b>const</b> <a href="jwks.md#0x1_jwks_ENATIVE_NOT_ENOUGH_VOTING_POWER">ENATIVE_NOT_ENOUGH_VOTING_POWER</a>: u64 = 261;
664+
</code></pre>
665+
666+
667+
623668
<a id="0x1_jwks_EUNEXPECTED_EPOCH"></a>
624669

625670

aptos-move/framework/aptos-framework/sources/jwks.move

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ module aptos_framework::jwks {
2929
const EISSUER_NOT_FOUND: u64 = 5;
3030
const EJWK_ID_NOT_FOUND: u64 = 6;
3131

32+
const ENATIVE_MISSING_RESOURCE_VALIDATOR_SET: u64 = 0x0101;
33+
const ENATIVE_MISSING_RESOURCE_OBSERVED_JWKS: u64 = 0x0102;
34+
const ENATIVE_INCORRECT_VERSION: u64 = 0x0103;
35+
const ENATIVE_MULTISIG_VERIFICATION_FAILED: u64 = 0x0104;
36+
const ENATIVE_NOT_ENOUGH_VOTING_POWER: u64 = 0x0105;
37+
3238
/// An OIDC provider.
3339
struct OIDCProvider has drop, store {
3440
/// The utf-8 encoded issuer string. E.g., b"https://www.facebook.com".

aptos-move/framework/move-stdlib/doc/features.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ return true.
8888
- [Function `zkid_feature_enabled`](#0x1_features_zkid_feature_enabled)
8989
- [Function `get_zkid_zkless_feature`](#0x1_features_get_zkid_zkless_feature)
9090
- [Function `zkid_zkless_feature_enabled`](#0x1_features_zkid_zkless_feature_enabled)
91+
- [Function `get_jwk_consensus_feature`](#0x1_features_get_jwk_consensus_feature)
92+
- [Function `jwk_consensus_enabled`](#0x1_features_jwk_consensus_enabled)
9193
- [Function `change_feature_flags`](#0x1_features_change_feature_flags)
9294
- [Function `is_enabled`](#0x1_features_is_enabled)
9395
- [Function `set`](#0x1_features_set)
@@ -369,6 +371,18 @@ Lifetime: transient
369371

370372

371373

374+
<a id="0x1_features_JWK_CONSENSUS"></a>
375+
376+
The JWK consensus feature.
377+
378+
Lifetime: permanent
379+
380+
381+
<pre><code><b>const</b> <a href="features.md#0x1_features_JWK_CONSENSUS">JWK_CONSENSUS</a>: u64 = 49;
382+
</code></pre>
383+
384+
385+
372386
<a id="0x1_features_LIMIT_MAX_IDENTIFIER_LENGTH"></a>
373387

374388

@@ -1918,6 +1932,52 @@ Lifetime: transient
19181932

19191933

19201934

1935+
</details>
1936+
1937+
<a id="0x1_features_get_jwk_consensus_feature"></a>
1938+
1939+
## Function `get_jwk_consensus_feature`
1940+
1941+
1942+
1943+
<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_get_jwk_consensus_feature">get_jwk_consensus_feature</a>(): u64
1944+
</code></pre>
1945+
1946+
1947+
1948+
<details>
1949+
<summary>Implementation</summary>
1950+
1951+
1952+
<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_get_jwk_consensus_feature">get_jwk_consensus_feature</a>(): u64 { <a href="features.md#0x1_features_JWK_CONSENSUS">JWK_CONSENSUS</a> }
1953+
</code></pre>
1954+
1955+
1956+
1957+
</details>
1958+
1959+
<a id="0x1_features_jwk_consensus_enabled"></a>
1960+
1961+
## Function `jwk_consensus_enabled`
1962+
1963+
1964+
1965+
<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_jwk_consensus_enabled">jwk_consensus_enabled</a>(): bool
1966+
</code></pre>
1967+
1968+
1969+
1970+
<details>
1971+
<summary>Implementation</summary>
1972+
1973+
1974+
<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_jwk_consensus_enabled">jwk_consensus_enabled</a>(): bool <b>acquires</b> <a href="features.md#0x1_features_Features">Features</a> {
1975+
<a href="features.md#0x1_features_is_enabled">is_enabled</a>(<a href="features.md#0x1_features_JWK_CONSENSUS">JWK_CONSENSUS</a>)
1976+
}
1977+
</code></pre>
1978+
1979+
1980+
19211981
</details>
19221982

19231983
<a id="0x1_features_change_feature_flags"></a>

0 commit comments

Comments
 (0)