Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read only call #602

Merged
merged 6 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ packages/massa-web3/src/web3
packages/massa-web3/src/index.ts
packages/massa-web3/test

**/open_rpc/**
**/generated/**
**/dist/**
**/docs/**
4 changes: 2 additions & 2 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"dependencies": {
"@types/pbkdf2": "^3.1.2",
"big-varint": "^0.1.3",
"decimal.js": "^10.4.3",
"pbkdf2": "^3.1.2"
}
}
4 changes: 2 additions & 2 deletions packages/massa-web3/open_rpc/massa.api.json
Original file line number Diff line number Diff line change
Expand Up @@ -3114,7 +3114,7 @@
"type": "null"
},
{
"type": "number"
"type": "string"
}
]
},
Expand All @@ -3125,7 +3125,7 @@
"type": "null"
},
{
"type": "number"
"type": "string"
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export * from './operationManager'
export * from './operation'
export * from './storage'
export * from './args'
export * from './serializers'
export * as Mas from './mas'
export * from './serializers'
32 changes: 22 additions & 10 deletions packages/massa-web3/src/experimental/basicElements/mas.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import Decimal from 'decimal.js'
import { FIRST, ONE } from '../utils'
import { U64, fromNumber } from './serializers/number/u64'

const NB_DECIMALS = 9
export const NB_DECIMALS = 9
export const SIZE_U256_BIT = 256
const POWER_TEN = 10

export const ERROR_NOT_SAFE_INTEGER = 'value is not a safe integer.'
Expand Down Expand Up @@ -98,16 +100,26 @@

return fromNumber(mas)
}

/**
* Converts a value in the smallest unit of the Massa currency to a decimal value.
* Converts a Mas value to a string with rounding approximation.
*
* @param value - The Mas value.
* @param decimalPlaces - The number of decimal places to include in the string.
* @returns The value as a string.
*
* @param value - The value in the smallest unit of the Massa currency.
* @returns The decimal value.
* @throws An error if the value is too large to be represented by a U256.
*/
export function toString(value: Mas): string {
const valueString = value.toString()
const integerPart = valueString.slice(FIRST, -NB_DECIMALS) || '0'
const decimalPart = valueString.slice(-NB_DECIMALS).replace(/0+$/, '')
return `${integerPart}${decimalPart.length ? '.' + decimalPart : ''}`
export function toString(
value: Mas,
decimalPlaces: number | null = null
): string {
if (BigInt(value) >= BigInt(ONE) << BigInt(SIZE_U256_BIT)) {
throw new Error(ERROR_VALUE_TOO_LARGE)
}

Check warning on line 118 in packages/massa-web3/src/experimental/basicElements/mas.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch

const scaledValue = new Decimal(value.toString()).div(`1e+${NB_DECIMALS}`)

return decimalPlaces !== null
? scaledValue.toFixed(decimalPlaces, Decimal.ROUND_HALF_UP)
: scaledValue.toString()
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ export class OperationManager {
* @returns A byte array representing the serialized operation.
*/
static serialize(operation: OperationDetails): Uint8Array {
// TODO: check that unsigned.encode is equivalent to varint.encode
const components = [
unsigned.encode(operation.fee),
varint.encode(operation.expirePeriod),
Expand Down
30 changes: 29 additions & 1 deletion packages/massa-web3/src/experimental/client/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OperationStatus } from '../basicElements'
import { Address, OperationStatus } from '../basicElements'
import { Mas } from '../basicElements/mas'
import { U64 } from '../basicElements/serializers/number/u64'
import { NodeStatus, Slot } from '../generated/client'
Expand All @@ -23,6 +23,33 @@ export type EventFilter = {
isError?: boolean
}

export type ReadOnlyCallParams = {
func: string
target: Address
caller: Address
parameter?: Uint8Array
coins?: Mas
fee?: Mas
maxGas?: U64
}

export type ReadOnlyCallResult = {
value: Uint8Array
info: {
gasCost: number
error?: string
events: SCOutputEvent[]
stateChanges: {
ledgerChanges: Record<string, unknown>
asyncPoolChanges: Record<string, unknown>[]
posChanges: Record<string, unknown>
executedOpsChanges: Record<string, unknown>
executedDenunciationsChanges: Record<string, unknown>
executionTrailHashChange: string
}
}
}

/*
* Blockchain client functions needed by the Operation class to send operations to the blockchain.
*/
Expand All @@ -35,6 +62,7 @@ export interface BlockchainClient {
getEvents(filter: EventFilter): Promise<SCOutputEvent[]>
getChainId(): Promise<U64>
getMinimalFee(): Promise<Mas>
executeReadOnlyCall(params: ReadOnlyCallParams): Promise<ReadOnlyCallResult>
// TODO: change for a getter instead
status: NodeStatus
}
49 changes: 43 additions & 6 deletions packages/massa-web3/src/experimental/client/publicAPI.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Mas, OperationStatus } from '../basicElements'
import { SendOperationInput, EventFilter as EvtFilter } from '.'
import {
SendOperationInput,
EventFilter as EvtFilter,
ReadOnlyCallParams,
ReadOnlyCallResult,
} from '.'
import {
OperationInput,
Pagination,
Expand Down Expand Up @@ -40,6 +45,7 @@ type JSONAPIOptions = {
path?: string
protocol?: string
}

export class PublicAPI {
connector: MassaOpenRPCSpecification
status: NodeStatus
Expand Down Expand Up @@ -78,11 +84,42 @@ export class PublicAPI {
}

async executeReadOnlyCall(
readOnlyCall: ReadOnlyCall
): Promise<ExecuteReadOnlyResponse> {
return this.connector
.execute_read_only_call([readOnlyCall])
.then((r) => r[FIRST])
params: ReadOnlyCallParams
): Promise<ReadOnlyCallResult> {
const [res] = await this.connector.execute_read_only_call([
{
max_gas: Number(params.maxGas),
target_address: params.target.toString(),
target_function: params.func,
parameter: params.parameter ? Array.from(params.parameter) : [],
caller_address: params.caller.toString(),
coins: params.coins ? Mas.toString(params.coins) : null,
fee: params.fee ? Mas.toString(params.fee) : null,
Ben-Rey marked this conversation as resolved.
Show resolved Hide resolved
},
])

if (!res) {
throw new Error('No result returned from execute_read_only_call')
}

return {
value: (res.result.Ok as unknown as Uint8Array) ?? null,
info: {
gasCost: res.gas_cost,
error: res.result.Error,
events: res.output_events,
stateChanges: {
ledgerChanges: res.state_changes.ledger_changes,
asyncPoolChanges: res.state_changes.async_pool_changes,
posChanges: res.state_changes.pos_changes,
executedOpsChanges: res.state_changes.executed_ops_changes,
executedDenunciationsChanges:
res.state_changes.executed_denunciations_changes,
executionTrailHashChange:
res.state_changes.execution_trail_hash_change,
},
},
}
}

async executeMultipleReadOnlyCall(
Expand Down
Loading
Loading