chore: viewblock state investigation, swc stats

This commit is contained in:
ppedziwiatr
2021-09-30 11:34:55 +02:00
parent 64a3fc0794
commit 3809423ef4
17 changed files with 921477 additions and 6 deletions

View File

@@ -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) {

View File

@@ -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 {

View 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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

0
tools/data/test.txt Normal file
View File

View 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

File diff suppressed because it is too large Load Diff

9794
tools/data/validity_old.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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
View 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;
}

View File

@@ -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
View 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));