Skip to content

Commit a1cda42

Browse files
authored
* [resource-viewer] Add metering to resource viewer * bump node version
1 parent 9caaaa3 commit a1cda42

File tree

7 files changed

+183
-46
lines changed

7 files changed

+183
-46
lines changed

Cargo.lock

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

api/types/src/convert.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use move_core_types::{
4242
resolver::ModuleResolver,
4343
value::{MoveStructLayout, MoveTypeLayout},
4444
};
45-
use move_resource_viewer::MoveValueAnnotator;
45+
use move_resource_viewer::{Limiter, MoveValueAnnotator};
4646
use serde_json::Value;
4747
use std::{
4848
convert::{TryFrom, TryInto},
@@ -81,8 +81,13 @@ impl<'a, R: ModuleResolver + ?Sized> MoveConverter<'a, R> {
8181
&self,
8282
data: impl Iterator<Item = (StructTag, &'b [u8])>,
8383
) -> Result<Vec<MoveResource>> {
84-
data.map(|(typ, bytes)| self.try_into_resource(&typ, bytes))
85-
.collect()
84+
let mut limiter = Limiter::default();
85+
data.map(|(typ, bytes)| {
86+
self.inner
87+
.view_resource_with_limit(&typ, bytes, &mut limiter)?
88+
.try_into()
89+
})
90+
.collect()
8691
}
8792

8893
pub fn try_into_resource(&self, typ: &StructTag, bytes: &'_ [u8]) -> Result<MoveResource> {

aptos-node/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "aptos-node"
33
description = "Aptos node"
4-
version = "1.11.0"
4+
version = "1.11.2"
55

66
# Workspace inherited keys
77
authors = { workspace = true }

third_party/move/tools/move-resource-viewer/src/fat_type.rs

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// SPDX-License-Identifier: Apache-2.0
44
//! Loaded representation for runtime types.
55
6+
use crate::limit::Limiter;
67
use move_binary_format::{
78
errors::{PartialVMError, PartialVMResult},
89
file_format::AbilitySet,
@@ -72,7 +73,37 @@ pub(crate) enum FatType {
7273
}
7374

7475
impl FatStructType {
75-
pub fn subst(&self, ty_args: &[FatType]) -> PartialVMResult<FatStructType> {
76+
fn clone_with_limit(&self, limit: &mut Limiter) -> PartialVMResult<Self> {
77+
limit.charge(std::mem::size_of::<AccountAddress>())?;
78+
limit.charge(self.module.as_bytes().len())?;
79+
limit.charge(self.name.as_bytes().len())?;
80+
81+
Ok(Self {
82+
address: self.address,
83+
module: self.module.clone(),
84+
name: self.name.clone(),
85+
abilities: self.abilities,
86+
ty_args: self
87+
.ty_args
88+
.iter()
89+
.map(|ty| ty.clone_with_limit(limit))
90+
.collect::<PartialVMResult<_>>()?,
91+
layout: self
92+
.layout
93+
.iter()
94+
.map(|ty| ty.clone_with_limit(limit))
95+
.collect::<PartialVMResult<_>>()?,
96+
})
97+
}
98+
99+
pub fn subst(
100+
&self,
101+
ty_args: &[FatType],
102+
limiter: &mut Limiter,
103+
) -> PartialVMResult<FatStructType> {
104+
limiter.charge(std::mem::size_of::<AccountAddress>())?;
105+
limiter.charge(self.module.as_bytes().len())?;
106+
limiter.charge(self.name.as_bytes().len())?;
76107
Ok(Self {
77108
address: self.address,
78109
module: self.module.clone(),
@@ -81,22 +112,27 @@ impl FatStructType {
81112
ty_args: self
82113
.ty_args
83114
.iter()
84-
.map(|ty| ty.subst(ty_args))
115+
.map(|ty| ty.subst(ty_args, limiter))
85116
.collect::<PartialVMResult<_>>()?,
86117
layout: self
87118
.layout
88119
.iter()
89-
.map(|ty| ty.subst(ty_args))
120+
.map(|ty| ty.subst(ty_args, limiter))
90121
.collect::<PartialVMResult<_>>()?,
91122
})
92123
}
93124

94-
pub fn struct_tag(&self) -> PartialVMResult<StructTag> {
125+
pub fn struct_tag(&self, limiter: &mut Limiter) -> PartialVMResult<StructTag> {
95126
let ty_args = self
96127
.ty_args
97128
.iter()
98-
.map(|ty| ty.type_tag())
129+
.map(|ty| ty.type_tag(limiter))
99130
.collect::<PartialVMResult<Vec<_>>>()?;
131+
132+
limiter.charge(std::mem::size_of::<AccountAddress>())?;
133+
limiter.charge(self.module.as_bytes().len())?;
134+
limiter.charge(self.name.as_bytes().len())?;
135+
100136
Ok(StructTag {
101137
address: self.address,
102138
module: self.module.clone(),
@@ -107,12 +143,32 @@ impl FatStructType {
107143
}
108144

109145
impl FatType {
110-
pub fn subst(&self, ty_args: &[FatType]) -> PartialVMResult<FatType> {
146+
fn clone_with_limit(&self, limit: &mut Limiter) -> PartialVMResult<Self> {
147+
use FatType::*;
148+
Ok(match self {
149+
TyParam(idx) => TyParam(*idx),
150+
Bool => Bool,
151+
U8 => U8,
152+
U16 => U16,
153+
U32 => U32,
154+
U64 => U64,
155+
U128 => U128,
156+
U256 => U256,
157+
Address => Address,
158+
Signer => Signer,
159+
Vector(ty) => Vector(Box::new(ty.clone_with_limit(limit)?)),
160+
Reference(ty) => Reference(Box::new(ty.clone_with_limit(limit)?)),
161+
MutableReference(ty) => MutableReference(Box::new(ty.clone_with_limit(limit)?)),
162+
Struct(struct_ty) => Struct(Box::new(struct_ty.clone_with_limit(limit)?)),
163+
})
164+
}
165+
166+
pub fn subst(&self, ty_args: &[FatType], limit: &mut Limiter) -> PartialVMResult<FatType> {
111167
use FatType::*;
112168

113169
let res = match self {
114170
TyParam(idx) => match ty_args.get(*idx) {
115-
Some(ty) => ty.clone(),
171+
Some(ty) => ty.clone_with_limit(limit)?,
116172
None => {
117173
return Err(
118174
PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
@@ -134,17 +190,17 @@ impl FatType {
134190
U256 => U256,
135191
Address => Address,
136192
Signer => Signer,
137-
Vector(ty) => Vector(Box::new(ty.subst(ty_args)?)),
138-
Reference(ty) => Reference(Box::new(ty.subst(ty_args)?)),
139-
MutableReference(ty) => MutableReference(Box::new(ty.subst(ty_args)?)),
193+
Vector(ty) => Vector(Box::new(ty.subst(ty_args, limit)?)),
194+
Reference(ty) => Reference(Box::new(ty.subst(ty_args, limit)?)),
195+
MutableReference(ty) => MutableReference(Box::new(ty.subst(ty_args, limit)?)),
140196

141-
Struct(struct_ty) => Struct(Box::new(struct_ty.subst(ty_args)?)),
197+
Struct(struct_ty) => Struct(Box::new(struct_ty.subst(ty_args, limit)?)),
142198
};
143199

144200
Ok(res)
145201
}
146202

147-
pub fn type_tag(&self) -> PartialVMResult<TypeTag> {
203+
pub fn type_tag(&self, limit: &mut Limiter) -> PartialVMResult<TypeTag> {
148204
use FatType::*;
149205

150206
let res = match self {
@@ -157,8 +213,8 @@ impl FatType {
157213
U256 => TypeTag::U256,
158214
Address => TypeTag::Address,
159215
Signer => TypeTag::Signer,
160-
Vector(ty) => TypeTag::Vector(Box::new(ty.type_tag()?)),
161-
Struct(struct_ty) => TypeTag::Struct(Box::new(struct_ty.struct_tag()?)),
216+
Vector(ty) => TypeTag::Vector(Box::new(ty.type_tag(limit)?)),
217+
Struct(struct_ty) => TypeTag::Struct(Box::new(struct_ty.struct_tag(limit)?)),
162218

163219
Reference(_) | MutableReference(_) | TyParam(_) => {
164220
return Err(

third_party/move/tools/move-resource-viewer/src/lib.rs

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::{
77
resolver::Resolver,
88
};
99
use anyhow::{anyhow, Result};
10+
pub use limit::Limiter;
1011
use move_binary_format::{
1112
errors::{Location, PartialVMError},
1213
file_format::{Ability, AbilitySet},
@@ -30,6 +31,7 @@ use std::{
3031
};
3132

3233
mod fat_type;
34+
mod limit;
3335
mod module_cache;
3436
mod resolver;
3537

@@ -119,6 +121,7 @@ impl<'a, T: ModuleResolver + ?Sized> MoveValueAnnotator<'a, T> {
119121
ty_args: &[TypeTag],
120122
args: &[Vec<u8>],
121123
) -> Result<Vec<AnnotatedMoveValue>> {
124+
let mut limit = Limiter::default();
122125
let types: Vec<FatType> = self
123126
.cache
124127
.resolve_function_arguments(module, function)?
@@ -154,18 +157,29 @@ impl<'a, T: ModuleResolver + ?Sized> MoveValueAnnotator<'a, T> {
154157
.iter()
155158
.enumerate()
156159
.map(|(i, ty)| {
157-
ty.subst(&ty_args)
160+
ty.subst(&ty_args, &mut limit)
158161
.map_err(anyhow::Error::from)
159-
.and_then(|fat_type| self.view_value_by_fat_type(&fat_type, &args[i]))
162+
.and_then(|fat_type| {
163+
self.view_value_by_fat_type(&fat_type, &args[i], &mut limit)
164+
})
160165
})
161166
.collect::<Result<Vec<AnnotatedMoveValue>>>()
162167
}
163168

164169
pub fn view_resource(&self, tag: &StructTag, blob: &[u8]) -> Result<AnnotatedMoveStruct> {
170+
self.view_resource_with_limit(tag, blob, &mut Limiter::default())
171+
}
172+
173+
pub fn view_resource_with_limit(
174+
&self,
175+
tag: &StructTag,
176+
blob: &[u8],
177+
limit: &mut Limiter,
178+
) -> Result<AnnotatedMoveStruct> {
165179
let ty = self.cache.resolve_struct(tag)?;
166180
let struct_def = (&ty).try_into().map_err(into_vm_status)?;
167181
let move_struct = MoveStruct::simple_deserialize(blob, &struct_def)?;
168-
self.annotate_struct(&move_struct, &ty)
182+
self.annotate_struct(&move_struct, &ty, limit)
169183
}
170184

171185
pub fn move_struct_fields(
@@ -187,28 +201,38 @@ impl<'a, T: ModuleResolver + ?Sized> MoveValueAnnotator<'a, T> {
187201
}
188202

189203
pub fn view_value(&self, ty_tag: &TypeTag, blob: &[u8]) -> Result<AnnotatedMoveValue> {
190-
let ty = self.cache.resolve_type(ty_tag)?;
191-
self.view_value_by_fat_type(&ty, blob)
204+
let mut limit = Limiter::default();
205+
let ty = self.cache.resolve_type_impl(ty_tag, &mut limit)?;
206+
self.view_value_by_fat_type(&ty, blob, &mut limit)
192207
}
193208

194-
fn view_value_by_fat_type(&self, ty: &FatType, blob: &[u8]) -> Result<AnnotatedMoveValue> {
209+
fn view_value_by_fat_type(
210+
&self,
211+
ty: &FatType,
212+
blob: &[u8],
213+
limit: &mut Limiter,
214+
) -> Result<AnnotatedMoveValue> {
195215
let layout = ty.try_into().map_err(into_vm_status)?;
196216
let move_value = MoveValue::simple_deserialize(blob, &layout)?;
197-
self.annotate_value(&move_value, ty)
217+
self.annotate_value(&move_value, ty, limit)
198218
}
199219

200220
fn annotate_struct(
201221
&self,
202222
move_struct: &MoveStruct,
203223
ty: &FatStructType,
224+
limit: &mut Limiter,
204225
) -> Result<AnnotatedMoveStruct> {
205226
let struct_tag = ty
206-
.struct_tag()
227+
.struct_tag(limit)
207228
.map_err(|e| e.finish(Location::Undefined).into_vm_status())?;
208229
let field_names = self.cache.get_field_names(ty)?;
230+
for names in field_names.iter() {
231+
limit.charge(names.as_bytes().len())?;
232+
}
209233
let mut annotated_fields = vec![];
210234
for (ty, v) in ty.layout.iter().zip(move_struct.fields().iter()) {
211-
annotated_fields.push(self.annotate_value(v, ty)?);
235+
annotated_fields.push(self.annotate_value(v, ty, limit)?);
212236
}
213237
Ok(AnnotatedMoveStruct {
214238
abilities: ty.abilities.0,
@@ -217,7 +241,12 @@ impl<'a, T: ModuleResolver + ?Sized> MoveValueAnnotator<'a, T> {
217241
})
218242
}
219243

220-
fn annotate_value(&self, value: &MoveValue, ty: &FatType) -> Result<AnnotatedMoveValue> {
244+
fn annotate_value(
245+
&self,
246+
value: &MoveValue,
247+
ty: &FatType,
248+
limit: &mut Limiter,
249+
) -> Result<AnnotatedMoveValue> {
221250
Ok(match (value, ty) {
222251
(MoveValue::Bool(b), FatType::Bool) => AnnotatedMoveValue::Bool(*b),
223252
(MoveValue::U8(i), FatType::U8) => AnnotatedMoveValue::U8(*i),
@@ -237,14 +266,14 @@ impl<'a, T: ModuleResolver + ?Sized> MoveValueAnnotator<'a, T> {
237266
.collect::<Result<_>>()?,
238267
),
239268
_ => AnnotatedMoveValue::Vector(
240-
ty.type_tag().unwrap(),
269+
ty.type_tag(limit).unwrap(),
241270
a.iter()
242-
.map(|v| self.annotate_value(v, ty.as_ref()))
271+
.map(|v| self.annotate_value(v, ty.as_ref(), limit))
243272
.collect::<Result<_>>()?,
244273
),
245274
},
246275
(MoveValue::Struct(s), FatType::Struct(ty)) => {
247-
AnnotatedMoveValue::Struct(self.annotate_struct(s, ty.as_ref())?)
276+
AnnotatedMoveValue::Struct(self.annotate_struct(s, ty.as_ref(), limit)?)
248277
},
249278
(MoveValue::U8(_), _)
250279
| (MoveValue::U64(_), _)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) The Move Contributors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use move_binary_format::errors::{PartialVMError, PartialVMResult};
5+
use move_core_types::vm_status::StatusCode;
6+
7+
// Default limit set to 100mb per query.
8+
const DEFAULT_LIMIT: usize = 100_000_000;
9+
10+
pub struct Limiter(usize);
11+
12+
impl Limiter {
13+
pub fn charge(&mut self, cost: usize) -> PartialVMResult<()> {
14+
if self.0 < cost {
15+
return Err(PartialVMError::new(StatusCode::ABORTED)
16+
.with_message("Query exceeds size limit".to_string()));
17+
}
18+
self.0 -= cost;
19+
Ok(())
20+
}
21+
}
22+
23+
impl Default for Limiter {
24+
fn default() -> Self {
25+
Limiter(DEFAULT_LIMIT)
26+
}
27+
}

0 commit comments

Comments
 (0)