Skip to content

Commit

Permalink
[json-rpc] Add get_event_by_version_with_proof
Browse files Browse the repository at this point in the history
  • Loading branch information
phlip9 authored and bors-libra committed Jul 12, 2021
1 parent ac39ce0 commit 825d773
Show file tree
Hide file tree
Showing 12 changed files with 296 additions and 11 deletions.
5 changes: 5 additions & 0 deletions json-rpc/API-CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ Please add the API change in the following format:
```

## 2021-07-07 Add `get_event_by_version_with_proof` API

This new API allows light clients to request an event at or below a version.
Concretely, light clients can now fully support `get_metadata` by using this API.

## 2021-06-08 Add `get_account_transactions_with_proofs` API

This new API allows verifying client users to get transactions under an account
Expand Down
93 changes: 93 additions & 0 deletions json-rpc/docs/method_get_event_by_version_with_proof.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
## Method get_event_by_version_with_proof

**Description**

Fetch the latest event at or below the given `version` from the given event `key`.
The response also includes cryptographic proofs needed to verify that the response
is correct.


### Parameters

| Name | Type | Description |
|---------|----------------|------------------------------------------------------------------------------------------------------|
| key | string | Globally unique identifier of an event stream |
| version | unsigned int64 | Return the latest event at or below this version. If unset, defaults to the server's current version |


### Returns

Returns an `EventByVersionWithProofView`, which contains two optional fields
denoting the lower bound inclusive `EventWithProofView` and upper bound exclusive
`EventWithProofView`. There are four possible cases for these two response fields:

1. There are no events at all in this event stream.
2. The given `version` is less than the first ever event's version for this event stream.
3. The given `version` is bounded in the range: `[lower_bound_incl.version, upper_bound_excl.version)`.
4. The given `version` is at or above the latest ever event's version to this event stream.


Example JSON-RPC responses:

Case (1.):
```json
{
"id": 1,
"jsonrpc": "2.0",
"diem_chain_id": 4,
"diem_ledger_timestampusec": 1608143037098724,
"diem_ledger_version": 100,
"result": {}
}
```

Case (2.):
```json
{
"id": 1,
"jsonrpc": "2.0",
"diem_chain_id": 4,
"diem_ledger_timestampusec": 1608143037098724,
"diem_ledger_version": 100,
"result": {
"upper_bound_excl": {
"event_with_proof": "00000000000000000000000000000000001800000000000000000000000000000000000000000a550c18000000000000000007000000000000000000000000000000010b4469656d4163636f756e74124372656174654163636f756e744576656e7400180000000000000000000000000a550c18000000000000000007205ea5bec9fcf7db9ca734b48ff2c30d333a47b265124e8f8d82c5933e99d38f4e20e2671b124cdd8bc5fdfdf9c3f385791c1e8e4b36cb9b7faa75a0aceffd2dc55420056518b61548197ec9cfdef5ccc9df06d7fbf9a65929ca6a001a6ba3e94e29f62057304aafb410c2e4903517fa60a60b644adac57a3531a647bffcf4f31370174c20cd295ff537e3415397ffcf822d89dd024be06c98c66ce1dd20c0452aab8e21bd201323a27e3b440505760f098720f643944b57516dff978701849ab53c6ccb6ab420cd150532557fe95d883e30dbd2723f41f85384de0993a24b81098a6d141fcd4020284bcdb5381519e4bd76634814026598babc7629d4f9ba827e4c6ae25557d25e209f181a5a463b39e5be659ebc0f5174936f3b8f34a443b98239ffeb43f5ec79a32063935d32737f16a01bf69f5a2df0fed9e1e659a1ac66a421cc7515884a24b61d00000000000000000004204d70a96fb83a2dcf437dd9e3dc9fb80d671a6ea84cd91aa047d7039d56383ad220b0068256b82f6f2cd8056967798b4c7a589ac1f8062a39d227b4ceb3530a8ff420d222a263f1142ed5089ddf8694b9fa98e981e891e63fd28f05d8d80f03a207de2000a98c24050c7371aa9ddde3f8b4263f83c41b94781b181a96db4b61e2ecdf19"
}
}
}
```

Case (3.):
```json
{
"id": 1,
"jsonrpc": "2.0",
"diem_chain_id": 4,
"diem_ledger_timestampusec": 1608143037098724,
"diem_ledger_version": 100,
"result": {
"lower_bound_incl": {
"event_with_proof": "00000000000000000100000000000000001800000000000000000000000000000000000000000a550c18010000000000000007000000000000000000000000000000010b4469656d4163636f756e74124372656174654163636f756e744576656e7400180000000000000000000000000b1e55ed010000000000000007205ea5bec9fcf7db9ca734b48ff2c30d333a47b265124e8f8d82c5933e99d38f4e20e2671b124cdd8bc5fdfdf9c3f385791c1e8e4b36cb9b7faa75a0aceffd2dc55420056518b61548197ec9cfdef5ccc9df06d7fbf9a65929ca6a001a6ba3e94e29f62057304aafb410c2e4903517fa60a60b644adac57a3531a647bffcf4f31370174c20cd295ff537e3415397ffcf822d89dd024be06c98c66ce1dd20c0452aab8e21bd201323a27e3b440505760f098720f643944b57516dff978701849ab53c6ccb6ab420cd150532557fe95d883e30dbd2723f41f85384de0993a24b81098a6d141fcd4020284bcdb5381519e4bd76634814026598babc7629d4f9ba827e4c6ae25557d25e209f181a5a463b39e5be659ebc0f5174936f3b8f34a443b98239ffeb43f5ec79a32063935d32737f16a01bf69f5a2df0fed9e1e659a1ac66a421cc7515884a24b61d00000000000000000004203296918711e9dfa27434d4bff7b9d489947392bad89d55eea0361c6d5884582f20b0068256b82f6f2cd8056967798b4c7a589ac1f8062a39d227b4ceb3530a8ff420d222a263f1142ed5089ddf8694b9fa98e981e891e63fd28f05d8d80f03a207de2000a98c24050c7371aa9ddde3f8b4263f83c41b94781b181a96db4b61e2ecdf19"
},
"upper_bound_excl": {
"event_with_proof": "00000000000000000200000000000000001800000000000000000000000000000000000000000a550c18020000000000000007000000000000000000000000000000010b4469656d4163636f756e74124372656174654163636f756e744576656e740018b5b333aabbf92e78524e2129b722eaca030000000000000007205ea5bec9fcf7db9ca734b48ff2c30d333a47b265124e8f8d82c5933e99d38f4e20e2671b124cdd8bc5fdfdf9c3f385791c1e8e4b36cb9b7faa75a0aceffd2dc55420056518b61548197ec9cfdef5ccc9df06d7fbf9a65929ca6a001a6ba3e94e29f62057304aafb410c2e4903517fa60a60b644adac57a3531a647bffcf4f31370174c20cd295ff537e3415397ffcf822d89dd024be06c98c66ce1dd20c0452aab8e21bd201323a27e3b440505760f098720f643944b57516dff978701849ab53c6ccb6ab420cd150532557fe95d883e30dbd2723f41f85384de0993a24b81098a6d141fcd4020284bcdb5381519e4bd76634814026598babc7629d4f9ba827e4c6ae25557d25e209f181a5a463b39e5be659ebc0f5174936f3b8f34a443b98239ffeb43f5ec79a32063935d32737f16a01bf69f5a2df0fed9e1e659a1ac66a421cc7515884a24b61d0000000000000000000420235cffb4a169efa7079e0f525485e1a15814dc7837c58b23cb957de765d3245720c3f7508f672153ca6689abb7b0a5c5e7249f492ba82aefeabd4bba44b56e35d020d222a263f1142ed5089ddf8694b9fa98e981e891e63fd28f05d8d80f03a207de2000a98c24050c7371aa9ddde3f8b4263f83c41b94781b181a96db4b61e2ecdf19"
}
}
}
```

Case (4.):
```json
{
"id": 1,
"jsonrpc": "2.0",
"diem_chain_id": 4,
"diem_ledger_timestampusec": 1608143037098724,
"diem_ledger_version": 100,
"result": {
"lower_bound_incl": {
"event_with_proof": "00000000000000000200000000000000001800000000000000000000000000000000000000000a550c18020000000000000007000000000000000000000000000000010b4469656d4163636f756e74124372656174654163636f756e744576656e740018b5b333aabbf92e78524e2129b722eaca030000000000000007205ea5bec9fcf7db9ca734b48ff2c30d333a47b265124e8f8d82c5933e99d38f4e20e2671b124cdd8bc5fdfdf9c3f385791c1e8e4b36cb9b7faa75a0aceffd2dc55420056518b61548197ec9cfdef5ccc9df06d7fbf9a65929ca6a001a6ba3e94e29f62057304aafb410c2e4903517fa60a60b644adac57a3531a647bffcf4f31370174c20cd295ff537e3415397ffcf822d89dd024be06c98c66ce1dd20c0452aab8e21bd201323a27e3b440505760f098720f643944b57516dff978701849ab53c6ccb6ab420cd150532557fe95d883e30dbd2723f41f85384de0993a24b81098a6d141fcd4020284bcdb5381519e4bd76634814026598babc7629d4f9ba827e4c6ae25557d25e209f181a5a463b39e5be659ebc0f5174936f3b8f34a443b98239ffeb43f5ec79a32063935d32737f16a01bf69f5a2df0fed9e1e659a1ac66a421cc7515884a24b61d0000000000000000000420235cffb4a169efa7079e0f525485e1a15814dc7837c58b23cb957de765d3245720c3f7508f672153ca6689abb7b0a5c5e7249f492ba82aefeabd4bba44b56e35d020d222a263f1142ed5089ddf8694b9fa98e981e891e63fd28f05d8d80f03a207de2000a98c24050c7371aa9ddde3f8b4263f83c41b94781b181a96db4b61e2ecdf19"
},
}
}
```
36 changes: 34 additions & 2 deletions json-rpc/integration-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@
// SPDX-License-Identifier: Apache-2.0

use diem_sdk::{
client::views::{AccountTransactionsWithProofView, AccumulatorConsistencyProofView, EventView},
client::views::{
AccountTransactionsWithProofView, AccumulatorConsistencyProofView,
EventByVersionWithProofView, EventView,
},
crypto::{hash::CryptoHash, HashValue},
transaction_builder::{stdlib, Currency},
types::{
access_path::AccessPath,
account_address::AccountAddress,
account_config::{treasury_compliance_account_address, xus_tag},
contract_event::EventWithProof,
block_metadata::new_block_event_key,
contract_event::{EventByVersionWithProof, EventWithProof},
diem_id_identifier::DiemIdVaspDomainIdentifier,
event::EventKey,
ledger_info::LedgerInfoWithSignatures,
Expand Down Expand Up @@ -1698,6 +1702,34 @@ impl PublicUsageTest for GetEventsWithProofs {
}
}

pub struct GetEventByVersionWithProofTest;

impl Test for GetEventByVersionWithProofTest {
fn name(&self) -> &'static str {
"jsonrpc::get-event-by-version-with-proof-test"
}
}

impl PublicUsageTest for GetEventByVersionWithProofTest {
fn run<'t>(&self, ctx: &mut PublicUsageContext<'t>) -> Result<()> {
let env = JsonRpcTestHelper::new(ctx.url().to_owned());

let event_key = new_block_event_key();
let response = env.send(
"get_event_by_version_with_proof",
json!([event_key.to_string()]),
);

// Just check that the responses deserialize correctly, we'll let
// the verifying client smoke tests handle the proof checking.
let value = response.result.unwrap();
let view = serde_json::from_value::<EventByVersionWithProofView>(value).unwrap();
let _proof = EventByVersionWithProof::try_from(&view).unwrap();

Ok(())
}
}

pub struct MultiAgentPaymentOverDualAttestationLimit;

impl Test for MultiAgentPaymentOverDualAttestationLimit {
Expand Down
1 change: 1 addition & 0 deletions json-rpc/integration-tests/tests/jsonrpc-forge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ fn main() -> Result<()> {
&GetTransactionsWithProofs,
&GetTreasuryComplianceAccount,
&GetEventsWithProofs,
&GetEventByVersionWithProofTest,
&MultiAgentPaymentOverDualAttestationLimit,
&GetAccumulatorConsistencyProof,
&NoUnknownEvents,
Expand Down
16 changes: 14 additions & 2 deletions json-rpc/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::{
errors::JsonRpcError,
views::{
AccountStateWithProofView, AccountTransactionsWithProofView, AccountView,
AccumulatorConsistencyProofView, CurrencyInfoView, EventView, EventWithProofView,
MetadataView, StateProofView, TransactionListView, TransactionView,
AccumulatorConsistencyProofView, CurrencyInfoView, EventByVersionWithProofView, EventView,
EventWithProofView, MetadataView, StateProofView, TransactionListView, TransactionView,
TransactionsWithProofsView,
},
};
Expand Down Expand Up @@ -228,6 +228,18 @@ pub fn get_events_with_proofs(
Ok(views)
}

/// Returns the latest event at or below the requested version along with proof.
pub fn get_event_by_version_with_proof(
db: &dyn DbReader,
ledger_version: u64,
event_key: EventKey,
version: u64,
) -> Result<EventByVersionWithProofView, JsonRpcError> {
let event_by_version =
db.get_event_by_version_with_proof(&event_key, version, ledger_version)?;
EventByVersionWithProofView::try_from(&event_by_version).map_err(Into::into)
}

/// Returns meta information about supported currencies
pub fn get_currencies(
db: &dyn DbReader,
Expand Down
32 changes: 27 additions & 5 deletions json-rpc/src/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use crate::{
errors::JsonRpcError,
views::{
AccountStateWithProofView, AccountTransactionsWithProofView, AccountView,
AccumulatorConsistencyProofView, CurrencyInfoView, EventView, EventWithProofView,
MetadataView, StateProofView, TransactionListView, TransactionView,
AccumulatorConsistencyProofView, CurrencyInfoView, EventByVersionWithProofView, EventView,
EventWithProofView, MetadataView, StateProofView, TransactionListView, TransactionView,
TransactionsWithProofsView,
},
};
Expand All @@ -17,9 +17,10 @@ use diem_config::config::RoleType;
use diem_json_rpc_types::request::{
GetAccountParams, GetAccountStateWithProofParams, GetAccountTransactionParams,
GetAccountTransactionsParams, GetAccountTransactionsWithProofsParams,
GetAccumulatorConsistencyProofParams, GetCurrenciesParams, GetEventsParams,
GetEventsWithProofsParams, GetMetadataParams, GetNetworkStatusParams, GetStateProofParams,
GetTransactionsParams, GetTransactionsWithProofsParams, MethodRequest, SubmitParams,
GetAccumulatorConsistencyProofParams, GetCurrenciesParams, GetEventByVersionWithProof,
GetEventsParams, GetEventsWithProofsParams, GetMetadataParams, GetNetworkStatusParams,
GetStateProofParams, GetTransactionsParams, GetTransactionsWithProofsParams, MethodRequest,
SubmitParams,
};
use diem_mempool::{MempoolClientSender, SubmissionStatus};
use diem_types::{
Expand Down Expand Up @@ -185,6 +186,9 @@ impl<'a> Handler<'a> {
MethodRequest::GetEventsWithProofs(params) => {
serde_json::to_value(self.get_events_with_proofs(params).await?)?
}
MethodRequest::GetEventByVersionWithProof(params) => {
serde_json::to_value(self.get_event_by_version_with_proof(params).await?)?
}
};
Ok(response)
}
Expand Down Expand Up @@ -350,6 +354,24 @@ impl<'a> Handler<'a> {
data::get_events_with_proofs(self.service.db.borrow(), self.version(), key, start, limit)
}

/// Returns the latest event at or below the requested version along with proof.
async fn get_event_by_version_with_proof(
&self,
params: GetEventByVersionWithProof,
) -> Result<EventByVersionWithProofView, JsonRpcError> {
let GetEventByVersionWithProof { key, version } = params;

let version = self.version_param(version, "version")?;
let ledger_version = self.version();

data::get_event_by_version_with_proof(
self.service.db.borrow(),
ledger_version,
key,
version,
)
}

/// Returns meta information about supported currencies
async fn get_currencies(
&self,
Expand Down
16 changes: 16 additions & 0 deletions json-rpc/src/tests/unit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,22 @@ fn test_json_rpc_protocol_invalid_requests() {
"diem_ledger_version": version
}),
),
(
"get_event_by_version_with_proof: version is too large",
json!({"jsonrpc": "2.0", "method": "get_event_by_version_with_proof", "params": ["13000000000000000000000000000000000000000a550c18", version+1], "id": 1}),
json!({
"error": {
"code": -32602,
"message": format!("Invalid param version should be <= known latest version {}", version),
"data": null
},
"id": 1,
"jsonrpc": "2.0",
"diem_chain_id": ChainId::test().id(),
"diem_ledger_timestampusec": timestamp,
"diem_ledger_version": version
}),
),
(
"get_account_transaction: invalid account",
json!({"jsonrpc": "2.0", "method": "get_account_transaction", "params": ["invalid", 1, false], "id": 1}),
Expand Down
16 changes: 16 additions & 0 deletions json-rpc/types/proto/src/jsonrpc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -436,3 +436,19 @@ message AccountTransactionsWithProof {
// list of hex-encoded bcs bytes
repeated string serialized_txns_with_proofs = 1 [json_name="serialized_txns_with_proofs"];
}

/**
* This is for the experimental API get_events_with_proofs response. It is unstable and likely to be changed.
*/
message EventWithProof {
// hex-encoded bcs bytes
string event_with_proof = 1 [json_name="event_with_proof"];
}

/**
* This is for the experimental API get_event_by_version_with_proof response. It is unstable and likely to be changed.
*/
message EventByVersionWithProof {
EventWithProof lower_bound_incl = 1 [json_name="lower_bound_incl"];
EventWithProof upper_bound_excl = 2 [json_name="upper_bound_excl"];
}
2 changes: 2 additions & 0 deletions json-rpc/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub enum Method {
GetTransactionsWithProofs,
GetAccountTransactionsWithProofs,
GetEventsWithProofs,
GetEventByVersionWithProof,
}

impl Method {
Expand All @@ -77,6 +78,7 @@ impl Method {
Method::GetTransactionsWithProofs => "get_transactions_with_proofs",
Method::GetAccountTransactionsWithProofs => "get_account_transactions_with_proofs",
Method::GetEventsWithProofs => "get_events_with_proofs",
Method::GetEventByVersionWithProof => "get_event_by_version_with_proof",
}
}
}
41 changes: 41 additions & 0 deletions json-rpc/types/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pub enum MethodRequest {
GetTransactionsWithProofs(GetTransactionsWithProofsParams),
GetAccountTransactionsWithProofs(GetAccountTransactionsWithProofsParams),
GetEventsWithProofs(GetEventsWithProofsParams),
GetEventByVersionWithProof(GetEventByVersionWithProof),
}

impl MethodRequest {
Expand Down Expand Up @@ -120,6 +121,9 @@ impl MethodRequest {
Method::GetEventsWithProofs => {
MethodRequest::GetEventsWithProofs(serde_json::from_value(value)?)
}
Method::GetEventByVersionWithProof => {
MethodRequest::GetEventByVersionWithProof(serde_json::from_value(value)?)
}
};

Ok(method_request)
Expand All @@ -146,6 +150,7 @@ impl MethodRequest {
Method::GetAccountTransactionsWithProofs
}
MethodRequest::GetEventsWithProofs(_) => Method::GetEventsWithProofs,
MethodRequest::GetEventByVersionWithProof(_) => Method::GetEventByVersionWithProof,
}
}
}
Expand Down Expand Up @@ -361,6 +366,13 @@ pub struct GetEventsWithProofsParams {
pub limit: u64,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GetEventByVersionWithProof {
pub key: EventKey,
#[serde(default)]
pub version: Option<u64>,
}

#[cfg(test)]
mod test {
use super::*;
Expand Down Expand Up @@ -945,4 +957,33 @@ mod test {
"foo": 11,
}));
}

#[test]
fn get_event_by_version_with_proof() {
let parse = |value| serde_json::from_value::<GetEventByVersionWithProof>(value);
let parse_ok = |value| parse(value).unwrap();
let parse_err = |value| parse(value).unwrap_err();

let key = "13000000000000000000000000000000000000000a550c18";

// Correct arguments
parse_ok(json!([key, 10]));
parse_ok(json!([key]));

// Incorrect arguments
parse_err(json!([key, 10, false]));
parse_err(json!(["foo", 10]));
parse_err(json!([]));
parse_err(json!({}));

// Object params
parse_ok(json!({ "key": key, "version": 10 }));
parse_ok(json!({ "key": key }));

// Object without all required params
parse_err(json!({ "version": 10 }));

// Object with more params
parse_ok(json!({ "key": key, "version": 10, "foo": 99 }));
}
}
Loading

0 comments on commit 825d773

Please sign in to comment.