fix: update ar gw bundled contracts loader to handle legacy format
This commit is contained in:
@@ -36,6 +36,7 @@ export const WARP_TAGS = {
|
|||||||
WASM_META: 'Wasm-Meta',
|
WASM_META: 'Wasm-Meta',
|
||||||
REQUEST_VRF: 'Request-Vrf',
|
REQUEST_VRF: 'Request-Vrf',
|
||||||
SIGNATURE_TYPE: 'Signature-Type',
|
SIGNATURE_TYPE: 'Signature-Type',
|
||||||
|
UPLOADER_TX_ID: 'Uploader-Tx-Id',
|
||||||
WARP_TESTNET: 'Warp-Testnet',
|
WARP_TESTNET: 'Warp-Testnet',
|
||||||
MANIFEST: 'Contract-Manifest',
|
MANIFEST: 'Contract-Manifest',
|
||||||
NONCE: 'Nonce'
|
NONCE: 'Nonce'
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { ArweaveWrapper } from '../../../utils/ArweaveWrapper';
|
|||||||
import { sleep } from '../../../utils/utils';
|
import { sleep } from '../../../utils/utils';
|
||||||
import { Benchmark } from '../../../logging/Benchmark';
|
import { Benchmark } from '../../../logging/Benchmark';
|
||||||
import { Warp } from '../../Warp';
|
import { Warp } from '../../Warp';
|
||||||
|
import { WARP_TAGS } from '../../KnownTags';
|
||||||
|
|
||||||
const TRANSACTIONS_QUERY = `query Transactions($tags: [TagFilter!]!, $blockFilter: BlockFilter!, $first: Int!, $after: String) {
|
const TRANSACTIONS_QUERY = `query Transactions($tags: [TagFilter!]!, $blockFilter: BlockFilter!, $first: Int!, $after: String) {
|
||||||
transactions(tags: $tags, block: $blockFilter, first: $first, sort: HEIGHT_ASC, after: $after) {
|
transactions(tags: $tags, block: $blockFilter, first: $first, sort: HEIGHT_ASC, after: $after) {
|
||||||
@@ -56,6 +57,33 @@ const TRANSACTION_QUERY = `query Transaction($id: ID!) {
|
|||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
// this is a query for old/legacy bundler format
|
||||||
|
const TRANSACTION_QUERY_USING_TAG = `query Transactions($tags: [TagFilter!]!) {
|
||||||
|
transactions(tags: $tags) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
owner { address, key }
|
||||||
|
recipient
|
||||||
|
tags {
|
||||||
|
name
|
||||||
|
value
|
||||||
|
}
|
||||||
|
block {
|
||||||
|
height
|
||||||
|
id
|
||||||
|
timestamp
|
||||||
|
}
|
||||||
|
fee { winston, ar }
|
||||||
|
quantity { winston, ar }
|
||||||
|
parent { id }
|
||||||
|
bundledIn { id }
|
||||||
|
signature
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
|
||||||
interface TagFilter {
|
interface TagFilter {
|
||||||
name: string;
|
name: string;
|
||||||
values: string[];
|
values: string[];
|
||||||
@@ -93,6 +121,23 @@ export class ArweaveGQLTxsFetcher {
|
|||||||
return response.transaction;
|
return response.transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches transaction stored using legacy bundling format.
|
||||||
|
*/
|
||||||
|
async transactionUsingUploaderTag(transactionId: string): Promise<GQLTransaction> {
|
||||||
|
const txTag: TagFilter = {
|
||||||
|
name: WARP_TAGS.UPLOADER_TX_ID,
|
||||||
|
values: [transactionId]
|
||||||
|
};
|
||||||
|
const response = (await this.fetch<GQLResultInterface['data']>(TRANSACTION_QUERY_USING_TAG, { tags: [txTag] }))
|
||||||
|
.transactions;
|
||||||
|
|
||||||
|
if (response.edges.length < 1) {
|
||||||
|
throw new Error(`No interaction with tag ${WARP_TAGS.UPLOADER_TX_ID}:${transactionId}`);
|
||||||
|
}
|
||||||
|
return response.edges[0].node;
|
||||||
|
}
|
||||||
|
|
||||||
async transactions(variables: ArweaveTransactionQuery): Promise<GQLEdgeInterface[]> {
|
async transactions(variables: ArweaveTransactionQuery): Promise<GQLEdgeInterface[]> {
|
||||||
let pageResult = (await this.fetch<GQLResultInterface['data']>(TRANSACTIONS_QUERY, variables)).transactions;
|
let pageResult = (await this.fetch<GQLResultInterface['data']>(TRANSACTIONS_QUERY, variables)).transactions;
|
||||||
const edges: GQLEdgeInterface[] = [...pageResult.edges];
|
const edges: GQLEdgeInterface[] = [...pageResult.edges];
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { DefinitionLoader } from '../DefinitionLoader';
|
|||||||
import { GW_TYPE } from '../InteractionsLoader';
|
import { GW_TYPE } from '../InteractionsLoader';
|
||||||
import { ArweaveGQLTxsFetcher } from './ArweaveGQLTxsFetcher';
|
import { ArweaveGQLTxsFetcher } from './ArweaveGQLTxsFetcher';
|
||||||
import { WasmSrc } from './wasm/WasmSrc';
|
import { WasmSrc } from './wasm/WasmSrc';
|
||||||
|
import Arweave from 'arweave';
|
||||||
|
|
||||||
function getTagValue(tags: GQLTagInterface[], tagName: string, orDefault = undefined) {
|
function getTagValue(tags: GQLTagInterface[], tagName: string, orDefault = undefined) {
|
||||||
const tag = tags.find(({ name }) => name === tagName);
|
const tag = tags.find(({ name }) => name === tagName);
|
||||||
@@ -32,7 +33,7 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
|
|||||||
|
|
||||||
async load<State>(contractTxId: string, evolvedSrcTxId?: string): Promise<ContractDefinition<State>> {
|
async load<State>(contractTxId: string, evolvedSrcTxId?: string): Promise<ContractDefinition<State>> {
|
||||||
const benchmark = Benchmark.measure();
|
const benchmark = Benchmark.measure();
|
||||||
const contractTx = await this.arweaveTransactions.transaction(contractTxId);
|
const contractTx: GQLTransaction = await this.fetchContractTx(contractTxId);
|
||||||
this.logger.debug('Contract tx fetch time', benchmark.elapsed());
|
this.logger.debug('Contract tx fetch time', benchmark.elapsed());
|
||||||
const owner = contractTx.owner.address;
|
const owner = contractTx.owner.address;
|
||||||
|
|
||||||
@@ -85,6 +86,14 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
|
|||||||
return contractDefinition;
|
return contractDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fetchContractTx(contractTxId: string): Promise<GQLTransaction | null> {
|
||||||
|
const txUsingId = await this.arweaveTransactions.transaction(contractTxId);
|
||||||
|
if (txUsingId == null) {
|
||||||
|
return await this.arweaveTransactions.transactionUsingUploaderTag(contractTxId);
|
||||||
|
}
|
||||||
|
return txUsingId;
|
||||||
|
}
|
||||||
|
|
||||||
private async convertToWarpCompatibleContractTx(gqlTransaction: GQLTransaction) {
|
private async convertToWarpCompatibleContractTx(gqlTransaction: GQLTransaction) {
|
||||||
const tags = gqlTransaction.tags.map(({ name, value }) => ({
|
const tags = gqlTransaction.tags.map(({ name, value }) => ({
|
||||||
name: Buffer.from(name).toString('base64url'),
|
name: Buffer.from(name).toString('base64url'),
|
||||||
@@ -103,7 +112,7 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
|
|||||||
async loadContractSource(srcTxId: string): Promise<ContractSource> {
|
async loadContractSource(srcTxId: string): Promise<ContractSource> {
|
||||||
const benchmark = Benchmark.measure();
|
const benchmark = Benchmark.measure();
|
||||||
|
|
||||||
const contractSrcTx = await this.arweaveTransactions.transaction(srcTxId);
|
const contractSrcTx = await this.fetchContractTx(srcTxId);
|
||||||
const srcContentType = getTagValue(contractSrcTx.tags, SMART_WEAVE_TAGS.CONTENT_TYPE);
|
const srcContentType = getTagValue(contractSrcTx.tags, SMART_WEAVE_TAGS.CONTENT_TYPE);
|
||||||
|
|
||||||
if (!SUPPORTED_SRC_CONTENT_TYPES.includes(srcContentType)) {
|
if (!SUPPORTED_SRC_CONTENT_TYPES.includes(srcContentType)) {
|
||||||
@@ -112,10 +121,7 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
|
|||||||
|
|
||||||
const contractType: ContractType = srcContentType === 'application/javascript' ? 'js' : 'wasm';
|
const contractType: ContractType = srcContentType === 'application/javascript' ? 'js' : 'wasm';
|
||||||
|
|
||||||
const src =
|
const src = await this.contractSource(contractSrcTx, contractType);
|
||||||
contractType === 'js'
|
|
||||||
? await this.arweaveWrapper.txDataString(srcTxId)
|
|
||||||
: await this.arweaveWrapper.txData(srcTxId);
|
|
||||||
|
|
||||||
let srcWasmLang: string | undefined;
|
let srcWasmLang: string | undefined;
|
||||||
let wasmSrc: WasmSrc;
|
let wasmSrc: WasmSrc;
|
||||||
@@ -124,7 +130,7 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
|
|||||||
wasmSrc = new WasmSrc(src as Buffer);
|
wasmSrc = new WasmSrc(src as Buffer);
|
||||||
srcWasmLang = getTagValue(contractSrcTx.tags, WARP_TAGS.WASM_LANG);
|
srcWasmLang = getTagValue(contractSrcTx.tags, WARP_TAGS.WASM_LANG);
|
||||||
if (!srcWasmLang) {
|
if (!srcWasmLang) {
|
||||||
throw new Error(`Wasm lang not set for wasm contract src ${srcTxId}`);
|
throw new Error(`Wasm lang not set for wasm contract src ${contractSrcTx.id}`);
|
||||||
}
|
}
|
||||||
srcMetaData = JSON.parse(getTagValue(contractSrcTx.tags, WARP_TAGS.WASM_META));
|
srcMetaData = JSON.parse(getTagValue(contractSrcTx.tags, WARP_TAGS.WASM_META));
|
||||||
}
|
}
|
||||||
@@ -142,6 +148,22 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async contractSource(contractSrcTx: GQLTransaction, contractType: ContractType): Promise<string | Buffer> {
|
||||||
|
const uploaderId = getTagValue(contractSrcTx.tags, WARP_TAGS.UPLOADER_TX_ID);
|
||||||
|
|
||||||
|
if (uploaderId != null) {
|
||||||
|
const txString = await this.arweaveWrapper.txDataString(contractSrcTx.id);
|
||||||
|
if (contractType === 'wasm') {
|
||||||
|
throw new Error('WASM contracts in legacy format are not supported using AR GW');
|
||||||
|
}
|
||||||
|
return Arweave.utils.b64UrlToString(JSON.parse(txString).data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return contractType === 'js'
|
||||||
|
? await this.arweaveWrapper.txDataString(contractSrcTx.id)
|
||||||
|
: await this.arweaveWrapper.txData(contractSrcTx.id);
|
||||||
|
}
|
||||||
|
|
||||||
private async evalInitialState(contractTx: GQLTransaction): Promise<string> {
|
private async evalInitialState(contractTx: GQLTransaction): Promise<string> {
|
||||||
if (getTagValue(contractTx.tags, WARP_TAGS.INIT_STATE)) {
|
if (getTagValue(contractTx.tags, WARP_TAGS.INIT_STATE)) {
|
||||||
return getTagValue(contractTx.tags, WARP_TAGS.INIT_STATE);
|
return getTagValue(contractTx.tags, WARP_TAGS.INIT_STATE);
|
||||||
|
|||||||
Reference in New Issue
Block a user