import * as $ from '@manahippo/move-to-ts'; import { AptosDataCache, AptosParserRepo, DummyCache, AptosLocalCache } from '@manahippo/move-to-ts'; import { U8, U64, U128 } from '@manahippo/move-to-ts'; import { u8, u64, u128 } from '@manahippo/move-to-ts'; import { TypeParamDeclType, FieldDeclType } from '@manahippo/move-to-ts'; import { AtomicTypeTag, StructTag, TypeTag, VectorTag, SimpleStructTag } from '@manahippo/move-to-ts'; import { OptionTransaction } from '@manahippo/move-to-ts'; import { HexString, AptosClient, AptosAccount, TxnBuilderTypes, Types } from 'aptos'; import * as Error from './error'; import * as State_storage from './state_storage'; import * as System_addresses from './system_addresses'; import * as Vector from './vector'; export const packageName = 'AptosFramework'; export const moduleAddress = new HexString('0x1'); export const moduleName = 'storage_gas'; export const BASIS_POINT_DENOMINATION: U64 = u64('10000'); export const EINVALID_GAS_RANGE: U64 = u64('2'); export const EINVALID_MONOTONICALLY_NON_DECREASING_CURVE: U64 = u64('5'); export const EINVALID_POINT_RANGE: U64 = u64('6'); export const ESTORAGE_GAS: U64 = u64('1'); export const ESTORAGE_GAS_CONFIG: U64 = u64('0'); export const ETARGET_USAGE_TOO_BIG: U64 = u64('4'); export const EZERO_TARGET_USAGE: U64 = u64('3'); export const MAX_U64: U64 = u64('18446744073709551615'); export class GasCurve { static moduleAddress = moduleAddress; static moduleName = moduleName; __app: $.AppType | null = null; static structName: string = 'GasCurve'; static typeParameters: TypeParamDeclType[] = []; static fields: FieldDeclType[] = [ { name: 'min_gas', typeTag: AtomicTypeTag.U64 }, { name: 'max_gas', typeTag: AtomicTypeTag.U64 }, { name: 'points', typeTag: new VectorTag(new StructTag(new HexString('0x1'), 'storage_gas', 'Point', [])) } ]; min_gas: U64; max_gas: U64; points: Point[]; constructor(proto: any, public typeTag: TypeTag) { this.min_gas = proto['min_gas'] as U64; this.max_gas = proto['max_gas'] as U64; this.points = proto['points'] as Point[]; } static GasCurveParser(data: any, typeTag: TypeTag, repo: AptosParserRepo): GasCurve { const proto = $.parseStructProto(data, typeTag, repo, GasCurve); return new GasCurve(proto, typeTag); } static getTag(): StructTag { return new StructTag(moduleAddress, moduleName, 'GasCurve', []); } async loadFullState(app: $.AppType) { this.__app = app; } } export class Point { static moduleAddress = moduleAddress; static moduleName = moduleName; __app: $.AppType | null = null; static structName: string = 'Point'; static typeParameters: TypeParamDeclType[] = []; static fields: FieldDeclType[] = [ { name: 'x', typeTag: AtomicTypeTag.U64 }, { name: 'y', typeTag: AtomicTypeTag.U64 } ]; x: U64; y: U64; constructor(proto: any, public typeTag: TypeTag) { this.x = proto['x'] as U64; this.y = proto['y'] as U64; } static PointParser(data: any, typeTag: TypeTag, repo: AptosParserRepo): Point { const proto = $.parseStructProto(data, typeTag, repo, Point); return new Point(proto, typeTag); } static getTag(): StructTag { return new StructTag(moduleAddress, moduleName, 'Point', []); } async loadFullState(app: $.AppType) { this.__app = app; } } export class StorageGas { static moduleAddress = moduleAddress; static moduleName = moduleName; __app: $.AppType | null = null; static structName: string = 'StorageGas'; static typeParameters: TypeParamDeclType[] = []; static fields: FieldDeclType[] = [ { name: 'per_item_read', typeTag: AtomicTypeTag.U64 }, { name: 'per_item_create', typeTag: AtomicTypeTag.U64 }, { name: 'per_item_write', typeTag: AtomicTypeTag.U64 }, { name: 'per_byte_read', typeTag: AtomicTypeTag.U64 }, { name: 'per_byte_create', typeTag: AtomicTypeTag.U64 }, { name: 'per_byte_write', typeTag: AtomicTypeTag.U64 } ]; per_item_read: U64; per_item_create: U64; per_item_write: U64; per_byte_read: U64; per_byte_create: U64; per_byte_write: U64; constructor(proto: any, public typeTag: TypeTag) { this.per_item_read = proto['per_item_read'] as U64; this.per_item_create = proto['per_item_create'] as U64; this.per_item_write = proto['per_item_write'] as U64; this.per_byte_read = proto['per_byte_read'] as U64; this.per_byte_create = proto['per_byte_create'] as U64; this.per_byte_write = proto['per_byte_write'] as U64; } static StorageGasParser(data: any, typeTag: TypeTag, repo: AptosParserRepo): StorageGas { const proto = $.parseStructProto(data, typeTag, repo, StorageGas); return new StorageGas(proto, typeTag); } static async load(repo: AptosParserRepo, client: AptosClient, address: HexString, typeParams: TypeTag[]) { const result = await repo.loadResource(client, address, StorageGas, typeParams); return result as unknown as StorageGas; } static async loadByApp(app: $.AppType, address: HexString, typeParams: TypeTag[]) { const result = await app.repo.loadResource(app.client, address, StorageGas, typeParams); await result.loadFullState(app); return result as unknown as StorageGas; } static getTag(): StructTag { return new StructTag(moduleAddress, moduleName, 'StorageGas', []); } async loadFullState(app: $.AppType) { this.__app = app; } } export class StorageGasConfig { static moduleAddress = moduleAddress; static moduleName = moduleName; __app: $.AppType | null = null; static structName: string = 'StorageGasConfig'; static typeParameters: TypeParamDeclType[] = []; static fields: FieldDeclType[] = [ { name: 'item_config', typeTag: new StructTag(new HexString('0x1'), 'storage_gas', 'UsageGasConfig', []) }, { name: 'byte_config', typeTag: new StructTag(new HexString('0x1'), 'storage_gas', 'UsageGasConfig', []) } ]; item_config: UsageGasConfig; byte_config: UsageGasConfig; constructor(proto: any, public typeTag: TypeTag) { this.item_config = proto['item_config'] as UsageGasConfig; this.byte_config = proto['byte_config'] as UsageGasConfig; } static StorageGasConfigParser(data: any, typeTag: TypeTag, repo: AptosParserRepo): StorageGasConfig { const proto = $.parseStructProto(data, typeTag, repo, StorageGasConfig); return new StorageGasConfig(proto, typeTag); } static async load(repo: AptosParserRepo, client: AptosClient, address: HexString, typeParams: TypeTag[]) { const result = await repo.loadResource(client, address, StorageGasConfig, typeParams); return result as unknown as StorageGasConfig; } static async loadByApp(app: $.AppType, address: HexString, typeParams: TypeTag[]) { const result = await app.repo.loadResource(app.client, address, StorageGasConfig, typeParams); await result.loadFullState(app); return result as unknown as StorageGasConfig; } static getTag(): StructTag { return new StructTag(moduleAddress, moduleName, 'StorageGasConfig', []); } async loadFullState(app: $.AppType) { await this.item_config.loadFullState(app); await this.byte_config.loadFullState(app); this.__app = app; } } export class UsageGasConfig { static moduleAddress = moduleAddress; static moduleName = moduleName; __app: $.AppType | null = null; static structName: string = 'UsageGasConfig'; static typeParameters: TypeParamDeclType[] = []; static fields: FieldDeclType[] = [ { name: 'target_usage', typeTag: AtomicTypeTag.U64 }, { name: 'read_curve', typeTag: new StructTag(new HexString('0x1'), 'storage_gas', 'GasCurve', []) }, { name: 'create_curve', typeTag: new StructTag(new HexString('0x1'), 'storage_gas', 'GasCurve', []) }, { name: 'write_curve', typeTag: new StructTag(new HexString('0x1'), 'storage_gas', 'GasCurve', []) } ]; target_usage: U64; read_curve: GasCurve; create_curve: GasCurve; write_curve: GasCurve; constructor(proto: any, public typeTag: TypeTag) { this.target_usage = proto['target_usage'] as U64; this.read_curve = proto['read_curve'] as GasCurve; this.create_curve = proto['create_curve'] as GasCurve; this.write_curve = proto['write_curve'] as GasCurve; } static UsageGasConfigParser(data: any, typeTag: TypeTag, repo: AptosParserRepo): UsageGasConfig { const proto = $.parseStructProto(data, typeTag, repo, UsageGasConfig); return new UsageGasConfig(proto, typeTag); } static getTag(): StructTag { return new StructTag(moduleAddress, moduleName, 'UsageGasConfig', []); } async loadFullState(app: $.AppType) { await this.read_curve.loadFullState(app); await this.create_curve.loadFullState(app); await this.write_curve.loadFullState(app); this.__app = app; } } export function base_8192_exponential_curve_(min_gas: U64, max_gas: U64, $c: AptosDataCache): GasCurve { return new_gas_curve_( $.copy(min_gas), $.copy(max_gas), [ new_point_(u64('1000'), u64('2'), $c), new_point_(u64('2000'), u64('6'), $c), new_point_(u64('3000'), u64('17'), $c), new_point_(u64('4000'), u64('44'), $c), new_point_(u64('5000'), u64('109'), $c), new_point_(u64('6000'), u64('271'), $c), new_point_(u64('7000'), u64('669'), $c), new_point_(u64('8000'), u64('1648'), $c), new_point_(u64('9000'), u64('4061'), $c), new_point_(u64('9500'), u64('6372'), $c), new_point_(u64('9900'), u64('9138'), $c) ], $c ); } export function calculate_create_gas_(config: UsageGasConfig, usage: U64, $c: AptosDataCache): U64 { return calculate_gas_($.copy(config.target_usage), $.copy(usage), config.create_curve, $c); } export function calculate_gas_(max_usage: U64, current_usage: U64, curve: GasCurve, $c: AptosDataCache): U64 { let temp$1, temp$10, temp$11, temp$12, temp$13, temp$2, temp$3, temp$4, temp$5, temp$6, temp$7, temp$8, temp$9, capped_current_usage, current_usage_bps, i, j, left, mid, num_points, points, right, y_interpolated; if ($.copy(current_usage).gt($.copy(max_usage))) { temp$1 = $.copy(max_usage); } else { temp$1 = $.copy(current_usage); } capped_current_usage = temp$1; points = curve.points; num_points = Vector.length_(points, $c, [new SimpleStructTag(Point)]); current_usage_bps = $.copy(capped_current_usage).mul($.copy(BASIS_POINT_DENOMINATION)).div($.copy(max_usage)); if ($.copy(num_points).eq(u64('0'))) { temp$3 = new Point({ x: u64('0'), y: u64('0') }, new SimpleStructTag(Point)); temp$4 = temp$3; temp$2 = new Point( { x: $.copy(BASIS_POINT_DENOMINATION), y: $.copy(BASIS_POINT_DENOMINATION) }, new SimpleStructTag(Point) ); [temp$12, temp$13] = [temp$4, temp$2]; } else { if ($.copy(current_usage_bps).lt($.copy(Vector.borrow_(points, u64('0'), $c, [new SimpleStructTag(Point)]).x))) { temp$5 = new Point({ x: u64('0'), y: u64('0') }, new SimpleStructTag(Point)); [temp$10, temp$11] = [temp$5, Vector.borrow_(points, u64('0'), $c, [new SimpleStructTag(Point)])]; } else { if ( $.copy(Vector.borrow_(points, $.copy(num_points).sub(u64('1')), $c, [new SimpleStructTag(Point)]).x).le( $.copy(current_usage_bps) ) ) { temp$7 = Vector.borrow_(points, $.copy(num_points).sub(u64('1')), $c, [new SimpleStructTag(Point)]); temp$6 = new Point( { x: $.copy(BASIS_POINT_DENOMINATION), y: $.copy(BASIS_POINT_DENOMINATION) }, new SimpleStructTag(Point) ); [temp$8, temp$9] = [temp$7, temp$6]; } else { [i, j] = [u64('0'), $.copy(num_points).sub(u64('2'))]; while (true) { { } if (!$.copy(i).lt($.copy(j))) break; { mid = $.copy(j).sub($.copy(j).sub($.copy(i)).div(u64('2'))); if ( $.copy(current_usage_bps).lt( $.copy(Vector.borrow_(points, $.copy(mid), $c, [new SimpleStructTag(Point)]).x) ) ) { j = $.copy(mid).sub(u64('1')); } else { i = $.copy(mid); } } } [temp$8, temp$9] = [ Vector.borrow_(points, $.copy(i), $c, [new SimpleStructTag(Point)]), Vector.borrow_(points, $.copy(i).add(u64('1')), $c, [new SimpleStructTag(Point)]) ]; } [temp$10, temp$11] = [temp$8, temp$9]; } [temp$12, temp$13] = [temp$10, temp$11]; } [left, right] = [temp$12, temp$13]; y_interpolated = interpolate_( $.copy(left.x), $.copy(right.x), $.copy(left.y), $.copy(right.y), $.copy(current_usage_bps), $c ); return interpolate_( u64('0'), $.copy(BASIS_POINT_DENOMINATION), $.copy(curve.min_gas), $.copy(curve.max_gas), $.copy(y_interpolated), $c ); } export function calculate_read_gas_(config: UsageGasConfig, usage: U64, $c: AptosDataCache): U64 { return calculate_gas_($.copy(config.target_usage), $.copy(usage), config.read_curve, $c); } export function calculate_write_gas_(config: UsageGasConfig, usage: U64, $c: AptosDataCache): U64 { return calculate_gas_($.copy(config.target_usage), $.copy(usage), config.write_curve, $c); } export function initialize_(aptos_framework: HexString, $c: AptosDataCache): void { let byte_config, item_config, k, m; System_addresses.assert_aptos_framework_(aptos_framework, $c); if (!!$c.exists(new SimpleStructTag(StorageGasConfig), new HexString('0x1'))) { throw $.abortCode(Error.already_exists_($.copy(ESTORAGE_GAS_CONFIG), $c)); } k = u64('1000'); m = u64('1000').mul(u64('1000')); item_config = new UsageGasConfig( { target_usage: u64('2').mul($.copy(k)).mul($.copy(m)), read_curve: base_8192_exponential_curve_( u64('300').mul($.copy(k)), u64('300').mul($.copy(k)).mul(u64('100')), $c ), create_curve: base_8192_exponential_curve_(u64('5').mul($.copy(m)), u64('5').mul($.copy(m)).mul(u64('100')), $c), write_curve: base_8192_exponential_curve_( u64('300').mul($.copy(k)), u64('300').mul($.copy(k)).mul(u64('100')), $c ) }, new SimpleStructTag(UsageGasConfig) ); byte_config = new UsageGasConfig( { target_usage: u64('1').mul($.copy(m)).mul($.copy(m)), read_curve: base_8192_exponential_curve_(u64('300'), u64('300').mul(u64('100')), $c), create_curve: base_8192_exponential_curve_(u64('5').mul($.copy(k)), u64('5').mul($.copy(k)).mul(u64('100')), $c), write_curve: base_8192_exponential_curve_(u64('5').mul($.copy(k)), u64('5').mul($.copy(k)).mul(u64('100')), $c) }, new SimpleStructTag(UsageGasConfig) ); $c.move_to( new SimpleStructTag(StorageGasConfig), aptos_framework, new StorageGasConfig( { item_config: $.copy(item_config), byte_config: $.copy(byte_config) }, new SimpleStructTag(StorageGasConfig) ) ); if (!!$c.exists(new SimpleStructTag(StorageGas), new HexString('0x1'))) { throw $.abortCode(Error.already_exists_($.copy(ESTORAGE_GAS), $c)); } $c.move_to( new SimpleStructTag(StorageGas), aptos_framework, new StorageGas( { per_item_read: u64('300').mul($.copy(k)), per_item_create: u64('5').mul($.copy(m)), per_item_write: u64('300').mul($.copy(k)), per_byte_read: u64('300'), per_byte_create: u64('5').mul($.copy(k)), per_byte_write: u64('5').mul($.copy(k)) }, new SimpleStructTag(StorageGas) ) ); return; } export function interpolate_(x0: U64, x1: U64, y0: U64, y1: U64, x: U64, $c: AptosDataCache): U64 { return $.copy(y0).add( $.copy(x) .sub($.copy(x0)) .mul($.copy(y1).sub($.copy(y0))) .div($.copy(x1).sub($.copy(x0))) ); } export function new_gas_curve_(min_gas: U64, max_gas: U64, points: Point[], $c: AptosDataCache): GasCurve { if (!$.copy(max_gas).ge($.copy(min_gas))) { throw $.abortCode(Error.invalid_argument_($.copy(EINVALID_GAS_RANGE), $c)); } if (!$.copy(max_gas).le($.copy(MAX_U64).div($.copy(BASIS_POINT_DENOMINATION)))) { throw $.abortCode(Error.invalid_argument_($.copy(EINVALID_GAS_RANGE), $c)); } validate_points_(points, $c); return new GasCurve( { min_gas: $.copy(min_gas), max_gas: $.copy(max_gas), points: $.copy(points) }, new SimpleStructTag(GasCurve) ); } export function new_point_(x: U64, y: U64, $c: AptosDataCache): Point { let temp$1; if ($.copy(x).le($.copy(BASIS_POINT_DENOMINATION))) { temp$1 = $.copy(y).le($.copy(BASIS_POINT_DENOMINATION)); } else { temp$1 = false; } if (!temp$1) { throw $.abortCode(Error.invalid_argument_($.copy(EINVALID_POINT_RANGE), $c)); } return new Point({ x: $.copy(x), y: $.copy(y) }, new SimpleStructTag(Point)); } export function new_storage_gas_config_( item_config: UsageGasConfig, byte_config: UsageGasConfig, $c: AptosDataCache ): StorageGasConfig { return new StorageGasConfig( { item_config: $.copy(item_config), byte_config: $.copy(byte_config) }, new SimpleStructTag(StorageGasConfig) ); } export function new_usage_gas_config_( target_usage: U64, read_curve: GasCurve, create_curve: GasCurve, write_curve: GasCurve, $c: AptosDataCache ): UsageGasConfig { if (!$.copy(target_usage).gt(u64('0'))) { throw $.abortCode(Error.invalid_argument_($.copy(EZERO_TARGET_USAGE), $c)); } if (!$.copy(target_usage).le($.copy(MAX_U64).div($.copy(BASIS_POINT_DENOMINATION)))) { throw $.abortCode(Error.invalid_argument_($.copy(ETARGET_USAGE_TOO_BIG), $c)); } return new UsageGasConfig( { target_usage: $.copy(target_usage), read_curve: $.copy(read_curve), create_curve: $.copy(create_curve), write_curve: $.copy(write_curve) }, new SimpleStructTag(UsageGasConfig) ); } export function on_reconfig_($c: AptosDataCache): void { let bytes, gas, gas_config, items; if (!$c.exists(new SimpleStructTag(StorageGasConfig), new HexString('0x1'))) { throw $.abortCode(Error.not_found_($.copy(ESTORAGE_GAS_CONFIG), $c)); } if (!$c.exists(new SimpleStructTag(StorageGas), new HexString('0x1'))) { throw $.abortCode(Error.not_found_($.copy(ESTORAGE_GAS), $c)); } [items, bytes] = State_storage.current_items_and_bytes_($c); gas_config = $c.borrow_global(new SimpleStructTag(StorageGasConfig), new HexString('0x1')); gas = $c.borrow_global_mut(new SimpleStructTag(StorageGas), new HexString('0x1')); gas.per_item_read = calculate_read_gas_(gas_config.item_config, $.copy(items), $c); gas.per_item_create = calculate_create_gas_(gas_config.item_config, $.copy(items), $c); gas.per_item_write = calculate_write_gas_(gas_config.item_config, $.copy(items), $c); gas.per_byte_read = calculate_read_gas_(gas_config.byte_config, $.copy(bytes), $c); gas.per_byte_create = calculate_create_gas_(gas_config.byte_config, $.copy(bytes), $c); gas.per_byte_write = calculate_write_gas_(gas_config.byte_config, $.copy(bytes), $c); return; } export function set_config_(aptos_framework: HexString, config: StorageGasConfig, $c: AptosDataCache): void { System_addresses.assert_aptos_framework_(aptos_framework, $c); $.set( $c.borrow_global_mut(new SimpleStructTag(StorageGasConfig), new HexString('0x1')), $.copy(config) ); return; } export function validate_points_(points: Point[], $c: AptosDataCache): void { let temp$1, temp$2, temp$3, temp$4, temp$5, cur, i, len, next; len = Vector.length_(points, $c, [new SimpleStructTag(Point)]); i = u64('0'); while (true) { { } if (!$.copy(i).le($.copy(len))) break; { if ($.copy(i).eq(u64('0'))) { temp$1 = new Point({ x: u64('0'), y: u64('0') }, new SimpleStructTag(Point)); temp$2 = temp$1; } else { temp$2 = Vector.borrow_(points, $.copy(i).sub(u64('1')), $c, [new SimpleStructTag(Point)]); } cur = temp$2; if ($.copy(i).eq($.copy(len))) { temp$3 = new Point( { x: $.copy(BASIS_POINT_DENOMINATION), y: $.copy(BASIS_POINT_DENOMINATION) }, new SimpleStructTag(Point) ); temp$4 = temp$3; } else { temp$4 = Vector.borrow_(points, $.copy(i), $c, [new SimpleStructTag(Point)]); } next = temp$4; if ($.copy(cur.x).lt($.copy(next.x))) { temp$5 = $.copy(cur.y).le($.copy(next.y)); } else { temp$5 = false; } if (!temp$5) { throw $.abortCode(Error.invalid_argument_($.copy(EINVALID_MONOTONICALLY_NON_DECREASING_CURVE), $c)); } i = $.copy(i).add(u64('1')); } } return; } export function loadParsers(repo: AptosParserRepo) { repo.addParser('0x1::storage_gas::GasCurve', GasCurve.GasCurveParser); repo.addParser('0x1::storage_gas::Point', Point.PointParser); repo.addParser('0x1::storage_gas::StorageGas', StorageGas.StorageGasParser); repo.addParser('0x1::storage_gas::StorageGasConfig', StorageGasConfig.StorageGasConfigParser); repo.addParser('0x1::storage_gas::UsageGasConfig', UsageGasConfig.UsageGasConfigParser); } export class App { constructor(public client: AptosClient, public repo: AptosParserRepo, public cache: AptosLocalCache) {} get moduleAddress() { { return moduleAddress; } } get moduleName() { { return moduleName; } } get GasCurve() { return GasCurve; } get Point() { return Point; } get StorageGas() { return StorageGas; } async loadStorageGas(owner: HexString, loadFull = true, fillCache = true) { const val = await StorageGas.load(this.repo, this.client, owner, [] as TypeTag[]); if (loadFull) { await val.loadFullState(this); } if (fillCache) { this.cache.set(val.typeTag, owner, val); } return val; } get StorageGasConfig() { return StorageGasConfig; } async loadStorageGasConfig(owner: HexString, loadFull = true, fillCache = true) { const val = await StorageGasConfig.load(this.repo, this.client, owner, [] as TypeTag[]); if (loadFull) { await val.loadFullState(this); } if (fillCache) { this.cache.set(val.typeTag, owner, val); } return val; } get UsageGasConfig() { return UsageGasConfig; } }