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',
|
||||
REQUEST_VRF: 'Request-Vrf',
|
||||
SIGNATURE_TYPE: 'Signature-Type',
|
||||
UPLOADER_TX_ID: 'Uploader-Tx-Id',
|
||||
WARP_TESTNET: 'Warp-Testnet',
|
||||
MANIFEST: 'Contract-Manifest',
|
||||
NONCE: 'Nonce'
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ArweaveWrapper } from '../../../utils/ArweaveWrapper';
|
||||
import { sleep } from '../../../utils/utils';
|
||||
import { Benchmark } from '../../../logging/Benchmark';
|
||||
import { Warp } from '../../Warp';
|
||||
import { WARP_TAGS } from '../../KnownTags';
|
||||
|
||||
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) {
|
||||
@@ -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 {
|
||||
name: string;
|
||||
values: string[];
|
||||
@@ -93,6 +121,23 @@ export class ArweaveGQLTxsFetcher {
|
||||
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[]> {
|
||||
let pageResult = (await this.fetch<GQLResultInterface['data']>(TRANSACTIONS_QUERY, variables)).transactions;
|
||||
const edges: GQLEdgeInterface[] = [...pageResult.edges];
|
||||
|
||||
@@ -17,6 +17,7 @@ import { DefinitionLoader } from '../DefinitionLoader';
|
||||
import { GW_TYPE } from '../InteractionsLoader';
|
||||
import { ArweaveGQLTxsFetcher } from './ArweaveGQLTxsFetcher';
|
||||
import { WasmSrc } from './wasm/WasmSrc';
|
||||
import Arweave from 'arweave';
|
||||
|
||||
function getTagValue(tags: GQLTagInterface[], tagName: string, orDefault = undefined) {
|
||||
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>> {
|
||||
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());
|
||||
const owner = contractTx.owner.address;
|
||||
|
||||
@@ -85,6 +86,14 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
|
||||
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) {
|
||||
const tags = gqlTransaction.tags.map(({ name, value }) => ({
|
||||
name: Buffer.from(name).toString('base64url'),
|
||||
@@ -103,7 +112,7 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
|
||||
async loadContractSource(srcTxId: string): Promise<ContractSource> {
|
||||
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);
|
||||
|
||||
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 src =
|
||||
contractType === 'js'
|
||||
? await this.arweaveWrapper.txDataString(srcTxId)
|
||||
: await this.arweaveWrapper.txData(srcTxId);
|
||||
const src = await this.contractSource(contractSrcTx, contractType);
|
||||
|
||||
let srcWasmLang: string | undefined;
|
||||
let wasmSrc: WasmSrc;
|
||||
@@ -124,7 +130,7 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
|
||||
wasmSrc = new WasmSrc(src as Buffer);
|
||||
srcWasmLang = getTagValue(contractSrcTx.tags, WARP_TAGS.WASM_LANG);
|
||||
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));
|
||||
}
|
||||
@@ -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> {
|
||||
if (getTagValue(contractTx.tags, WARP_TAGS.INIT_STATE)) {
|
||||
return getTagValue(contractTx.tags, WARP_TAGS.INIT_STATE);
|
||||
|
||||
Reference in New Issue
Block a user