chore: viewblock state investigation, swc stats
This commit is contained in:
@@ -220,6 +220,8 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
transfer.winstonQty
|
||||
);
|
||||
|
||||
this.logger.debug('interactionTx', interactionTx);
|
||||
|
||||
const response = await arweave.transactions.post(interactionTx);
|
||||
|
||||
if (response.status !== 200) {
|
||||
|
||||
@@ -11,6 +11,24 @@ const brokenTransactions = [
|
||||
'v6bGNzNMTb7fj_q_KwRyLH2pSN6rSmPzHXUvrfDPYHs',
|
||||
'vofahl_F506NkD6dP-1gYis-1N6sWQnfcXazDhoKaiQ',
|
||||
'z2fZzeB_466S9kTikjA2RihwEuBVUUe9FAceYj_KKtA',
|
||||
'nk1IIv4dM8ACzm9fwsxCKjngxWo4yMu6sqYr-Tqmp0I',
|
||||
'k0789IzsSppZl3egmQxX_Slx8VmMig4fQJaxyztVSV8',
|
||||
'lkjesyJ6Sr_flKak2FKd8As8FW-1k8wygRf8hjkTAfI',
|
||||
'2aHIKrdEvu-cUfalvOdcdqq79oVb41PBSgiAXr7epoc',
|
||||
'2QQxeYer5mranQLWBKLUGvbwhiqcGucAeB-puYB9hIM',
|
||||
'2VHl88d-YQWngGGhyBrluF5VNxY273_uE30AJ0qI_hY',
|
||||
'-3h01LpYQEd5bNXUfsSexYr-ak7G0ZPumLArZ-cuJ7I',
|
||||
'3qVrnEcApWEeVn4BDzN-aIDrAFIrPPTsQKbXxDYnquc',
|
||||
'4a9YiAXCavz22Gn0EFQ1_B9tNpRMUWvzsBeAarzR1c8',
|
||||
'50DJFXPa0l0mbjZDgqpghM9mz7CxGKez7kebvI79NJA',
|
||||
'7rqrFz3Jr8FZ5LYL2zSZbXrRvSXRwE8lZMpIOecKiag',
|
||||
'7sRE3KSkyhUYuU2ZaX-D5Sk5FQ2sF9KucwWZFu877fw',
|
||||
'8Fs-aLJgp8diQ5unp-hkli5oTBSDGnvQdIIrzfkCc0E',
|
||||
'8Yzk29D2JzwqYmwdA91z_ZqfG1jW2hXX1lhh3HY9fxY',
|
||||
'-b8gqnEsZp0AafO6tHTttTliGXu858vqolGs122dsaM',
|
||||
'_GR5BE5kae1JkCMUcbecJBuryqNzuAzd8BIVLey4CJA',
|
||||
'-k8bLMFysvyjKlakQaffbYyCSlZAGC7ZFq0KjhTVoKU',
|
||||
'-Q8A_3JXH3yZms7awAhK2PFCinWfCzm1gvaa6ogi6O4',
|
||||
]
|
||||
|
||||
export class FromFileInteractionsLoader implements InteractionsLoader {
|
||||
|
||||
107
tools/data/loot-contract-mods.js
Normal file
107
tools/data/loot-contract-mods.js
Normal file
@@ -0,0 +1,107 @@
|
||||
export async function handle(state, action) {
|
||||
|
||||
const COLORS = ["green", "red", "yellow", "blue", "black", "brown", "pink", "orange", "purple", "gray"];
|
||||
const MATERIALS = ["gold", "wood", "silver", "fire", "diamond", "platinum", "palladium", "bronze", "lithium", "titanium"];
|
||||
const ITEMS = ["sword", "shield", "robe", "stone", "crown", "katana", "dragon", "ring", "axe", "hammer"];
|
||||
|
||||
function bigIntFromBytes(byteArr) {
|
||||
let hexString = "";
|
||||
for (const byte of byteArr) {
|
||||
hexString += byte.toString(16).padStart(2, '0');
|
||||
}
|
||||
return BigInt("0x" + hexString);
|
||||
}
|
||||
|
||||
// This function calculates a pseudo-random int value,
|
||||
// which is less then the `max` argument.
|
||||
// Note! To correctly generate several random numbers in
|
||||
// a single contract interaction, you should pass different
|
||||
// values for the `uniqueValue` argument
|
||||
async function getRandomIntNumber(max, uniqueValue = "") {
|
||||
console.log('random input:', {
|
||||
max,
|
||||
uniqueValue,
|
||||
height: SmartWeave.block.height,
|
||||
timestamp: SmartWeave.block.timestamp,
|
||||
id: SmartWeave.transaction.id,
|
||||
caller: action.caller
|
||||
});
|
||||
|
||||
const pseudoRandomData = SmartWeave.arweave.utils.stringToBuffer(
|
||||
SmartWeave.block.height
|
||||
+ SmartWeave.block.timestamp
|
||||
+ SmartWeave.transaction.id
|
||||
+ action.caller
|
||||
+ uniqueValue
|
||||
);
|
||||
const hashBytes = await SmartWeave.arweave.crypto.hash(pseudoRandomData);
|
||||
const randomBigInt = bigIntFromBytes(hashBytes);
|
||||
const result = Number(randomBigInt % BigInt(max));
|
||||
console.log('random output:', {
|
||||
hashBytes,
|
||||
randomBigInt,
|
||||
result
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
switch (action.input.function) {
|
||||
|
||||
case "name": {
|
||||
return { result: state.name };
|
||||
}
|
||||
|
||||
case "generatedAssets": {
|
||||
return { result: Object.keys(state.assets) };
|
||||
}
|
||||
|
||||
case "assetsLeft": {
|
||||
const allAssetsCount = COLORS.length * MATERIALS.length * ITEMS.length;
|
||||
const generatedAssetsCount = Object.keys(state.assets).length;
|
||||
const assetsLeftCount = allAssetsCount - generatedAssetsCount;
|
||||
return { result: assetsLeftCount };
|
||||
}
|
||||
|
||||
case "getOwner": {
|
||||
const asset = action.input.data.asset;
|
||||
if (state.assets[asset]) {
|
||||
return { result: state.assets[asset] };
|
||||
} else {
|
||||
return { result: `The asset "${asset}" doesn't exist yet` };
|
||||
}
|
||||
}
|
||||
|
||||
case "generate": {
|
||||
console.log(`---- ${SmartWeave.transaction.id} ----`);
|
||||
const colorIndex = await getRandomIntNumber(COLORS.length, "color");
|
||||
const materialIndex = await getRandomIntNumber(MATERIALS.length, "material");
|
||||
const itemIndex = await getRandomIntNumber(ITEMS.length, "item");
|
||||
const asset = COLORS[colorIndex] + " " + MATERIALS[materialIndex] + " " + ITEMS[itemIndex];
|
||||
console.log('asset:', asset);
|
||||
if (!state.assets[asset]) {
|
||||
state.assets[asset] = action.caller;
|
||||
} else {
|
||||
throw new ContractError(
|
||||
`Generated item (${asset}) is already owned by: ${state.assets[asset]}`);
|
||||
}
|
||||
return { state };
|
||||
}
|
||||
|
||||
|
||||
case "transfer": {
|
||||
const toAddress = action.input.data.to;
|
||||
const asset = action.input.data.asset;
|
||||
if (state.assets[asset] !== action.caller) {
|
||||
throw new ContractError("Can not transfer asset that doesn't belong to sender");
|
||||
}
|
||||
state.assets[asset] = toAddress;
|
||||
return { state };
|
||||
}
|
||||
|
||||
default: {
|
||||
throw new ContractError(
|
||||
`Unsupported contract function: ${functionName}`);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
440447
tools/data/loot-logs-16.txt
Normal file
440447
tools/data/loot-logs-16.txt
Normal file
File diff suppressed because it is too large
Load Diff
440447
tools/data/loot-logs.txt
Normal file
440447
tools/data/loot-logs.txt
Normal file
File diff suppressed because it is too large
Load Diff
1005
tools/data/state_old.json
Normal file
1005
tools/data/state_old.json
Normal file
File diff suppressed because it is too large
Load Diff
1
tools/data/swc-stats.json
Normal file
1
tools/data/swc-stats.json
Normal file
File diff suppressed because one or more lines are too long
0
tools/data/test.txt
Normal file
0
tools/data/test.txt
Normal file
50
tools/data/transactions_test.json
Normal file
50
tools/data/transactions_test.json
Normal file
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"node": {
|
||||
"id": "p3PxOlmFEqKbM50RJWKmI7Ju3rm4QVOpxoI6pAY80VU",
|
||||
"owner": {
|
||||
"address": "FGxpWnJAB8XYbS5B7qIqk5sDMA80ChNuq70qMnTE-Sg"
|
||||
},
|
||||
"recipient": "",
|
||||
"tags": [
|
||||
{
|
||||
"name": "App-Name",
|
||||
"value": "SmartWeaveAction"
|
||||
},
|
||||
{
|
||||
"name": "App-Version",
|
||||
"value": "0.3.0"
|
||||
},
|
||||
{
|
||||
"name": "Contract",
|
||||
"value": "Daj-MNSnH55TDfxqC7v4eq0lKzVIwh98srUaWqyuZtY"
|
||||
},
|
||||
{
|
||||
"name": "Input",
|
||||
"value": "{\"function\":\"generate\"}"
|
||||
},
|
||||
{
|
||||
"name": "Signing-Client",
|
||||
"value": "ArConnect"
|
||||
},
|
||||
{
|
||||
"name": "Signing-Client-Version",
|
||||
"value": "0.3.5"
|
||||
}
|
||||
],
|
||||
"block": {
|
||||
"height": 776102,
|
||||
"id": "QxrqaGsa0SjMhMlmX6uxfU1P8fXm5qXC1T3q4oRe5oPY0SuxV7yulk_MRh89OCfm",
|
||||
"timestamp": 1632462654
|
||||
},
|
||||
"fee": {
|
||||
"winston": "1450156"
|
||||
},
|
||||
"quantity": {
|
||||
"winston": "0"
|
||||
},
|
||||
"parent": null
|
||||
},
|
||||
"cursor": "WyIyMDIxLTA5LTI0VDE3OjIxOjA2LjgxNloiLDFd"
|
||||
}
|
||||
]
|
||||
9794
tools/data/validity.json
Normal file
9794
tools/data/validity.json
Normal file
File diff suppressed because it is too large
Load Diff
9794
tools/data/validity_old.json
Normal file
9794
tools/data/validity_old.json
Normal file
File diff suppressed because it is too large
Load Diff
9794
tools/data/viewblock_smartweave_validity.json
Normal file
9794
tools/data/viewblock_smartweave_validity.json
Normal file
File diff suppressed because it is too large
Load Diff
9794
tools/data/viewblock_validity_email.json
Normal file
9794
tools/data/viewblock_validity_email.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { SmartWeaveWebFactory } from '../src/core/web/SmartWeaveWebFactory';
|
||||
import { FromFileInteractionsLoader } from './FromFileInteractionsLoader';
|
||||
import { readContract } from 'smartweave';
|
||||
|
||||
async function main() {
|
||||
LoggerFactory.use(new TsLogFactory());
|
||||
@@ -18,15 +19,26 @@ async function main() {
|
||||
logging: false // Enable network request logging
|
||||
});
|
||||
|
||||
const contractTxId = 'Daj-MNSnH55TDfxqC7v4eq0lKzVIwh98srUaWqyuZtY';
|
||||
|
||||
const interactionsLoader = new FromFileInteractionsLoader(path.join(__dirname, 'data', 'interactions.json'));
|
||||
|
||||
const smartweave = SmartWeaveWebFactory.memCachedBased(arweave).setInteractionsLoader(interactionsLoader).build();
|
||||
const smartweave = SmartWeaveWebFactory.memCachedBased(arweave)
|
||||
.setInteractionsLoader(interactionsLoader)
|
||||
.overwriteSource({
|
||||
[contractTxId]: fs.readFileSync(path.join(__dirname, 'data', 'loot-contract-mods.js'), 'utf-8')
|
||||
});
|
||||
|
||||
const lootContract = smartweave.contract('Daj-MNSnH55TDfxqC7v4eq0lKzVIwh98srUaWqyuZtY');
|
||||
const lootContract = smartweave.contract(contractTxId);
|
||||
|
||||
const { state } = await lootContract.readState();
|
||||
const { state, validity } = await lootContract.readState();
|
||||
|
||||
fs.writeFileSync(path.join(__dirname, 'data', 'loot.json'), JSON.stringify(state));
|
||||
//fs.writeFileSync(path.join(__dirname, 'data', 'validity.json'), JSON.stringify(validity));
|
||||
|
||||
//const result = await readContract(arweave, contractTxId, undefined, true);
|
||||
|
||||
//fs.writeFileSync(path.join(__dirname, 'data', 'validity_old.json'), JSON.stringify(result.validity));
|
||||
//fs.writeFileSync(path.join(__dirname, 'data', 'state_old.json'), JSON.stringify(result.state));
|
||||
}
|
||||
|
||||
main().catch((e) => console.error(e));
|
||||
|
||||
153
tools/swc-stats.ts
Normal file
153
tools/swc-stats.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import {
|
||||
ContractInteractionsLoader,
|
||||
GQLEdgeInterface,
|
||||
GQLResultInterface,
|
||||
GQLTransactionsResultInterface
|
||||
} from '@smartweave';
|
||||
import Arweave from 'arweave';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
// max number of results returned from single query.
|
||||
// If set more, arweave.net/graphql will still limit to 100 (not sure if that's a bug or feature).
|
||||
const MAX_RESULTS_PER_PAGE = 100;
|
||||
|
||||
const transactionsQuery = `
|
||||
query Transactions($tags: [TagFilter!]!, $after: String) {
|
||||
transactions(tags: $tags, first: 100, sort: HEIGHT_ASC, after: $after) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
tags {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
cursor
|
||||
}
|
||||
}
|
||||
}`;
|
||||
|
||||
const toSkip = ['C_1uo08qRuQAeDi9Y1I8fkaWYUC9IWkOrKDNe9EphJo',
|
||||
'B1SRLyFzWJjeA0ywW41Qu1j7ZpBLHsXSSrWLrT3ebd8'];
|
||||
|
||||
|
||||
async function main() {
|
||||
const arweave = Arweave.init({
|
||||
host: 'arweave.net', // Hostname or IP address for a Arweave host
|
||||
port: 443, // Port
|
||||
protocol: 'https', // Network protocol http or https
|
||||
timeout: 60000, // Network request timeouts in milliseconds
|
||||
logging: false // Enable network request logging
|
||||
});
|
||||
|
||||
const contractTxs = await sendQuery(
|
||||
arweave,
|
||||
{
|
||||
tags: [
|
||||
{
|
||||
name: 'App-Name',
|
||||
values: ['SmartWeaveContract']
|
||||
},
|
||||
{
|
||||
name: 'Content-Type',
|
||||
values: ['application/json']
|
||||
}
|
||||
],
|
||||
after: undefined
|
||||
},
|
||||
transactionsQuery
|
||||
);
|
||||
|
||||
console.log(`Checking ${contractTxs.length} contracts`);
|
||||
|
||||
const result = {};
|
||||
|
||||
const transactionsLoader = new ContractInteractionsLoader(arweave);
|
||||
|
||||
|
||||
// loading
|
||||
for (const contractTx of contractTxs) {
|
||||
const contractTxId = contractTx.node.id;
|
||||
if (toSkip.indexOf(contractTxId) !== -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`\n[${contractTxs.indexOf(contractTx) + 1} / ${contractTxs.length}] loading interactions of the ${contractTxId}`
|
||||
);
|
||||
const interactions = await transactionsLoader.load(contractTxId, 0, 779826);
|
||||
console.log(`${contractTxId}: ${interactions.length}`);
|
||||
|
||||
result[contractTxId] = interactions.length;
|
||||
fs.writeFileSync(path.join(__dirname, 'data', `swc-stats.json`), JSON.stringify(result));
|
||||
}
|
||||
|
||||
// fs.writeFileSync(path.join(__dirname, 'data', `swc-stats.json`), JSON.stringify(result));
|
||||
|
||||
// sorting
|
||||
console.log('Sorting...');
|
||||
|
||||
const contracts = JSON.parse(fs.readFileSync(path.join(__dirname, 'data', `swc-stats.json`), 'utf-8'));
|
||||
|
||||
const sortable = [];
|
||||
// tslint:disable-next-line:forin
|
||||
for (const contract in contracts) {
|
||||
sortable.push([contract, contracts[contract]]);
|
||||
}
|
||||
sortable.sort((a, b) => b[1] - a[1]);
|
||||
const sortedContracts = {};
|
||||
sortable.forEach((item) => (sortedContracts[item[0]] = item[1]));
|
||||
|
||||
console.log(sortedContracts);
|
||||
|
||||
fs.writeFileSync(path.join(__dirname, 'data', `swc-sorted-stats.json`), JSON.stringify(sortedContracts));
|
||||
}
|
||||
|
||||
main().then(() => {
|
||||
console.log('done');
|
||||
});
|
||||
|
||||
async function sendQuery(arweave: Arweave, variables: any, query: string) {
|
||||
let transactions: GQLTransactionsResultInterface | null = await getNextPage(arweave, variables, query);
|
||||
|
||||
const txs: GQLEdgeInterface[] = transactions.edges.filter((tx) => !tx.node.parent || !tx.node.parent.id);
|
||||
|
||||
while (transactions.pageInfo.hasNextPage) {
|
||||
const cursor = transactions.edges[MAX_RESULTS_PER_PAGE - 1].cursor;
|
||||
|
||||
variables = {
|
||||
...variables,
|
||||
after: cursor
|
||||
};
|
||||
|
||||
transactions = await getNextPage(arweave, variables, query);
|
||||
txs.push(...transactions.edges.filter((tx) => !tx.node.parent || !tx.node.parent.id));
|
||||
}
|
||||
|
||||
return txs;
|
||||
}
|
||||
|
||||
async function getNextPage(arweave, variables, query: string): Promise<GQLTransactionsResultInterface | null> {
|
||||
const response = await arweave.api.post('graphql', {
|
||||
query,
|
||||
variables
|
||||
});
|
||||
|
||||
if (response.status !== 200) {
|
||||
console.error(response);
|
||||
throw new Error(`Wrong response status from Arweave: ${response.status}`);
|
||||
}
|
||||
|
||||
if (response.data.errors) {
|
||||
console.error(response.data.errors);
|
||||
throw new Error('Error while loading transactions');
|
||||
}
|
||||
|
||||
const data: GQLResultInterface = response.data;
|
||||
|
||||
return data.data.transactions;
|
||||
}
|
||||
@@ -20,9 +20,11 @@ async function main() {
|
||||
|
||||
const transactionsLoader = new ContractInteractionsLoader(arweave);
|
||||
|
||||
const result = await transactionsLoader.load('Daj-MNSnH55TDfxqC7v4eq0lKzVIwh98srUaWqyuZtY', 769686, 769686);
|
||||
const result = await transactionsLoader.load('C_1uo08qRuQAeDi9Y1I8fkaWYUC9IWkOrKDNe9EphJo', 0, 779820);
|
||||
|
||||
fs.writeFileSync(path.join(__dirname, 'transactions.json'), JSON.stringify(result));
|
||||
console.log(result.length);
|
||||
|
||||
//fs.writeFileSync(path.join(__dirname, 'data', 'transactions-2.json'), JSON.stringify(result));
|
||||
}
|
||||
|
||||
main().catch((e) => console.error(e));
|
||||
|
||||
51
tools/write-check.ts
Normal file
51
tools/write-check.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import Arweave from 'arweave';
|
||||
import { LoggerFactory } from '../src';
|
||||
import { TsLogFactory } from '../src/logging/node/TsLogFactory';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { SmartWeaveWebFactory } from '../src/core/web/SmartWeaveWebFactory';
|
||||
import { FromFileInteractionsLoader } from './FromFileInteractionsLoader';
|
||||
import { readContract } from 'smartweave';
|
||||
import { readJSON } from '../../redstone-smartweave-examples/src/_utils';
|
||||
|
||||
async function main() {
|
||||
LoggerFactory.use(new TsLogFactory());
|
||||
LoggerFactory.INST.logLevel('debug');
|
||||
|
||||
const arweave = Arweave.init({
|
||||
host: 'dh48zl0solow5.cloudfront.net', // Hostname or IP address for a Arweave host
|
||||
port: 443, // Port
|
||||
protocol: 'https', // Network protocol http or https
|
||||
timeout: 60000, // Network request timeouts in milliseconds
|
||||
logging: false // Enable network request logging
|
||||
});
|
||||
|
||||
|
||||
const smartweave = SmartWeaveWebFactory.memCached(arweave);
|
||||
|
||||
const jwk = readJSON("../redstone-node/.secrets/redstone-jwk.json");
|
||||
|
||||
const token = smartweave
|
||||
.contract("lnG1-1_5lAoABx7oihhRXI3J5ybTTQ2HCi2FJbKPI_w")
|
||||
// connecting wallet to a contract. It is required before performing any "writeInteraction"
|
||||
// calling "writeInteraction" without connecting to a wallet first will cause a runtime error.
|
||||
.connect(jwk)
|
||||
.setEvaluationOptions({
|
||||
// with this flag set to true, the write will wait for the transaction to be confirmed
|
||||
waitForConfirmation: true,
|
||||
});
|
||||
|
||||
const result = await token.writeInteraction<any>({
|
||||
function: "transfer",
|
||||
data: {
|
||||
target: "fake",
|
||||
qty: 15100900,
|
||||
},
|
||||
});
|
||||
|
||||
//const { state, validity } = await lootContract.readState();
|
||||
|
||||
//fs.writeFileSync(path.join(__dirname, 'data', 'validity.json'), JSON.stringify(validity));
|
||||
}
|
||||
|
||||
main().catch((e) => console.error(e));
|
||||
Reference in New Issue
Block a user