Skip to content

Commit

Permalink
[API] POST /tables/<handle>/item
Browse files Browse the repository at this point in the history
  • Loading branch information
msmouse authored and aptos-bot committed Apr 27, 2022
1 parent 5829381 commit 301c2e6
Show file tree
Hide file tree
Showing 14 changed files with 451 additions and 58 deletions.
8 changes: 5 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ cached-framework-packages = { path = "../aptos-move/framework/cached-packages" }
executor = { path = "../execution/executor" }
executor-types = { path = "../execution/executor-types" }
mempool-notifications = { path = "../state-sync/inter-component/mempool-notifications" }
move-package = { git = "https://github.com/move-language/move", rev = "1b6b7513dcc1a5c866f178ca5c1e74beb2ce181e" }
vm-validator = { path = "../vm-validator" }

[features]
Expand Down
58 changes: 58 additions & 0 deletions api/doc/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,50 @@ paths:
$ref: '#/components/responses/404'
"500":
$ref: '#/components/responses/500'
/tables/{table_handle}/items:
post:
summary: Get table item by handle and key.
description: |
Gets a table item for a table identified by the handle and the key for the item.
Key and value types need to be passed in to help with key serialization and value deserialization.
operationId: get_table_item
tags:
- state
- table
parameters:
- name: table_handle
in: path
required: true
schema:
title: Table Handle
type: string
format: uint128
description: the table handle
example: "1283023094380"
requestBody:
description: Table item request
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TableItemRequest'
responses:
"200":
description: Returns the table item value rendered in JSON.
content:
application/json:
schema:
type: object
"400":
$ref: '#/components/responses/400'
"404":
$ref: '#/components/responses/404'
"413":
$ref: '#/components/responses/413'
"415":
$ref: '#/components/responses/415'
"500":
$ref: '#/components/responses/500'
components:
parameters:
AccountAddress:
Expand Down Expand Up @@ -1596,3 +1640,17 @@ components:
- $ref: '#/components/schemas/MultiEd25519Signature'
discriminator:
propertyName: type
TableItemRequest:
title: Table item request
type: object
required:
- key_type
- value_type
- key
properties:
key_type:
$ref: '#/components/schemas/MoveTypeId'
value_type:
$ref: '#/components/schemas/MoveTypeId'
key:
$ref: '#/components/schemas/MoveValue'
9 changes: 9 additions & 0 deletions api/move-test-package/Move.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "ApiTest"
version = "0.0.0"

[addresses]
# test user address to be installed dynamically on build

[dependencies]
AptosFramework = { local = "../../aptos-move/framework/aptos-framework" }
63 changes: 63 additions & 0 deletions api/move-test-package/sources/TableTestData.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/// This module provides test tables of various key / value types, for use in API tests
module TestAccount::TableTestData {
use 0x1::Table::{Self, Table};
use 0x1::ASCII;
use 0x1::GUID::{Self, ID};
use 0x1::Vector;

struct TestTables has key {
u8_table: Table<u8, u8>,
u64_table: Table<u64, u64>,
u128_table: Table<u128, u128>,
bool_table: Table<bool, bool>,
string_table: Table<ASCII::String, ASCII::String>,
address_table: Table<address, address>,
vector_u8_table: Table<vector<u8>, vector<u8>>,
vector_string_table: Table<vector<ASCII::String>, vector<ASCII::String>>,
id_table: Table<ID, ID>,
id_table_id: ID,
table_table: Table<u8, Table<u8, u8>>,
}

public(script) fun make_test_tables(account: signer) {
let id = GUID::id(&GUID::create(&account));
let str = ASCII::string(b"abc");
let vec_u8 = Vector::empty<u8>();
Vector::push_back(&mut vec_u8, 1);
Vector::push_back(&mut vec_u8, 2);
let vec_str = Vector::empty<ASCII::String>();
Vector::push_back(&mut vec_str, str);
Vector::push_back(&mut vec_str, str);
let table_u8 = Table::new();
Table::add(&mut table_u8, &2, 3);

let test_tables = TestTables {
u8_table: Table::new(),
u64_table: Table::new(),
u128_table: Table::new(),
bool_table: Table::new(),
string_table: Table::new(),
address_table: Table::new(),
vector_u8_table: Table::new(),
vector_string_table: Table::new(),
id_table: Table::new(),
id_table_id: copy id,
table_table: Table::new(),
};

let t = &mut test_tables;

Table::add(&mut t.u8_table, &1, 1);
Table::add(&mut t.u64_table, &1, 1);
Table::add(&mut t.u128_table, &1, 1);
Table::add(&mut t.bool_table, &true, true);
Table::add(&mut t.string_table, &str, copy str);
Table::add(&mut t.address_table, &@0x1, @0x1);
Table::add(&mut t.vector_u8_table, &vec_u8, copy vec_u8);
Table::add(&mut t.vector_string_table, &vec_str, copy vec_str);
Table::add(&mut t.id_table, &id, copy id);
Table::add(&mut t.table_table, &1, table_u8);

move_to(&account, test_tables);
}
}
1 change: 1 addition & 0 deletions api/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub fn routes(context: Context) -> impl Filter<Extract = impl Reply, Error = Inf
.or(events::get_events_by_event_handle(context.clone()))
.or(state::get_account_resource(context.clone()))
.or(state::get_account_module(context.clone()))
.or(state::get_table_item(context.clone()))
.or(context.health_check_route().with(metrics("health_check")))
.with(
warp::cors()
Expand Down
7 changes: 4 additions & 3 deletions api/src/param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ use serde::{Deserialize, Deserializer};
use std::{convert::Infallible, str::FromStr};

pub type AddressParam = Param<Address>;
pub type TransactionIdParam = Param<TransactionId>;
pub type TransactionVersionParam = Param<u64>;
pub type LedgerVersionParam = Param<u64>;
pub type EventKeyParam = Param<EventKey>;
pub type LedgerVersionParam = Param<u64>;
pub type MoveStructTagParam = Param<MoveStructTag>;
pub type MoveIdentifierParam = Param<Identifier>;
pub type TableHandleParam = Param<u128>;
pub type TransactionIdParam = Param<TransactionId>;
pub type TransactionVersionParam = Param<u64>;

/// `Param` is designed for parsing `warp` path parameter or query string
/// into a type specified by the generic type parameter of `Param`.
Expand Down
64 changes: 62 additions & 2 deletions api/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ use crate::{
context::Context,
failpoint::fail_point,
metrics::metrics,
param::{AddressParam, LedgerVersionParam, MoveIdentifierParam, MoveStructTagParam},
param::{
AddressParam, LedgerVersionParam, MoveIdentifierParam, MoveStructTagParam, TableHandleParam,
},
version::Version,
};
use anyhow::anyhow;
use aptos_api_types::{
AsConverter, Error, LedgerInfo, MoveModuleBytecode, Response, TransactionId,
AsConverter, Error, LedgerInfo, MoveModuleBytecode, Response, TableItemRequest, TransactionId,
};
use aptos_state_view::StateView;
use aptos_types::{access_path::AccessPath, state_store::state_key::StateKey};
Expand Down Expand Up @@ -51,6 +54,23 @@ pub fn get_account_module(context: Context) -> BoxedFilter<(impl Reply,)> {
.boxed()
}

// GET /tables/<table_handle>/item
pub fn get_table_item(context: Context) -> BoxedFilter<(impl Reply,)> {
warp::path!("tables" / TableHandleParam / "item")
.and(warp::post())
.and(warp::body::content_length_limit(
context.content_length_limit(),
))
.and(warp::body::json::<TableItemRequest>())
.and(context.filter())
.and(warp::query::<Version>())
.map(|handle, body, ctx, version: Version| (version.version, handle, body, ctx))
.untuple_one()
.and_then(handle_get_table_item)
.with(metrics("get_table_item"))
.boxed()
}

async fn handle_get_account_resource(
ledger_version: Option<LedgerVersionParam>,
address: AddressParam,
Expand Down Expand Up @@ -81,6 +101,16 @@ async fn handle_get_account_module(
)?)
}

async fn handle_get_table_item(
ledger_version: Option<LedgerVersionParam>,
handle: TableHandleParam,
body: TableItemRequest,
context: Context,
) -> Result<impl Reply, Rejection> {
fail_point("endpoint_get_table_item")?;
Ok(State::new(ledger_version, context)?.table_item(handle.parse("table handle")?, body)?)
}

pub(crate) struct State {
state_view: DbStateView,
ledger_version: aptos_types::transaction::Version,
Expand Down Expand Up @@ -149,4 +179,34 @@ impl State {
.map_err(Error::internal)?;
Response::new(self.latest_ledger_info, &module)
}

pub fn table_item(self, handle: u128, body: TableItemRequest) -> Result<impl Reply, Error> {
let TableItemRequest {
key_type,
value_type,
key,
} = body;
let key_type = key_type.try_into()?;
let value_type = value_type.try_into()?;

let resolver = self.state_view.as_move_resolver();
let converter = resolver.as_converter();

let vm_key = converter
.try_into_vm_value(&key_type, key.clone())
.map_err(Error::bad_request)?;
let raw_key = vm_key
.undecorate()
.simple_serialize()
.ok_or_else(|| Error::internal(anyhow!("Key failed to serialize.")))?;

let state_key = StateKey::table_item(handle, raw_key);
let bytes = self
.state_view
.get_state_value(&state_key)?
.ok_or_else(|| Error::not_found("table handle or item", key, self.ledger_version))?;

let move_value = converter.try_into_move_value(&value_type, &bytes)?;
Response::new(self.latest_ledger_info, &move_value)
}
}
Loading

0 comments on commit 301c2e6

Please sign in to comment.