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

Paima events #390

Merged
merged 22 commits into from
Jul 28, 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
43 changes: 43 additions & 0 deletions .verdaccio/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# path to a directory with all packages
storage: ../build/local-registry/storage

auth:
htpasswd:
file: ./htpasswd

# a list of other known repositories we can talk to
uplinks:
npmjs:
url: https://registry.npmjs.org/
maxage: 60m
max_fails: 20
fail_timeout: 2m
yarn:
url: https://registry.yarnpkg.com
maxage: 60m
max_fails: 20
fail_timeout: 2m

packages:
# for @paima packages, we never want to fallback to the npm registry
# otherwise, the local version will get rejected because the npm registry has a package with the same version
'@paima/*':
# allow all users full access (since it's a local registry)
access: $all
publish: $all
unpublish: $all

'**':
access: $all
publish: $all
unpublish: $all
proxy: npmjs # fallback to npmjs for non-paima package. This is needed for transitive dependencies to work

# log settings
log:
type: stdout
format: pretty
level: warn

publish:
allow_offline: true # set offline to true to allow publish offline
7 changes: 7 additions & 0 deletions nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@
},
"node-sdk": {
"projects": ["directory:packages/node-sdk/*"]
},
"others": {
"projects": [
"directory:packages/cardano-contracts/*",
"directory:packages/contracts/*",
"directory:packages/build-utils/*"
]
}
}
}
Expand Down
11,572 changes: 6,922 additions & 4,650 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,18 @@
"prebuild": "npx nx run-many --parallel=${NX_PARALLEL:-3} -t prebuild",
"build": "npm run lint:configs && npx nx run-many --parallel=${NX_PARALLEL:-3} -t build",
"test": "npm run lint:configs && npx nx run-many --parallel=${NX_PARALLEL:-3} -t test",
"clear:local": "npm set registry && ps aux | grep '[v]erdaccio' | awk '{print $2}' | xargs -r kill -9",
"release:local": "npm run build && npm run clear:local && npx ts-node ./tools/scripts/publish-local.ts",
"release:lib": "./wipe.sh && sh ./tools/scripts/bump-version.sh && npm run build && npm run lint && npm run test && read -p 'Enter OTP: ' otp && export NPM_CONFIG_OTP=$otp && npx nx release publish -g paima-sdk && npx nx release publish -g node-sdk",
"release:bin": "./wipe.sh && npm run lint:configs && npm run build && npx nx run-many --parallel=${NX_PARALLEL:-3} --projects=tag:type:binary -t release && mkdir -p ./bin && cp -rf ./packages/engine/paima-standalone/packaged/@standalone/* ./bin"
},
"devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.6.0",
"@nx/esbuild": "17.2.8",
"@nx/jest": "17.2.8",
"@nx/js": "17.2.8",
"@nx/linter": "17.2.8",
"@nx/esbuild": "19.5.1",
"@nx/jest": "19.5.1",
"@nx/js": "19.5.1",
"@nx/linter": "19.5.1",
"@types/eslint-plugin-prettier": "^3.1.3",
"@types/jest": "^29.5.10",
"@types/node": "^20.11.0",
Expand All @@ -40,14 +42,16 @@
"husky": "^8.0.3",
"jest": "29.7.0",
"json5": "^2.2.3",
"nx": "17.2.8",
"nx": "19.5.1",
"prettier": "^3.2.2",
"prettier-plugin-organize-imports": "^4.0.0",
"prettier-plugin-solidity": "^1.3.1",
"syncpack": "^11.2.1",
"tar": "^7.4.0",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
"typescript": "^5.5.3",
"verdaccio": "^5.31.1"
},
"overrides": {
"web3-eth-contract": "1.10.0"
Expand Down
2 changes: 1 addition & 1 deletion packages/admin-panel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@vitejs/plugin-react": "^1.3.0",
"typescript": "^5.3.3",
"typescript": "^5.5.3",
"vite": "^2.9.9"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ docker compose --env-file $ENV_FILE build
# so when using a localhost network, we instead run the paima-batcher directly on the machine
if [ -z "${NETWORK:-}" ] || [ "${NETWORK:-}" = "localhost" ]; then
cp ../.env.${NETWORK:-localhost} .
docker compose --env-file $ENV_FILE up paima-batcher-db & sleep 3 && $executable
docker compose --env-file $ENV_FILE up paima-batcher-db & sleep 3 && BATCHER_DB_HOST=localhost $executable
else
if [[ ! -f "./paima-batcher-linux" ]]; then
echo "Error: paima-batcher-linux binary not found. Docker requires the linux binary for the application."
Expand Down
5 changes: 3 additions & 2 deletions packages/batcher/batcher-transaction-poster/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"@types/pg": "^8.10.9"
},
"dependencies": {
"pg": "^8.11.3",
"@polkadot/util-crypto": "^12.6.2"
"@polkadot/util-crypto": "^12.6.2",
"mqtt": "^5.7.3",
"pg": "^8.11.3"
}
}
62 changes: 47 additions & 15 deletions packages/batcher/batcher-transaction-poster/src/avail.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { Pool } from 'pg';
import { base64Encode } from '@polkadot/util-crypto';
import BatchedTransactionPosterBase from './transactionPoster.js';
import { BatcherStatus } from '@paima/events';
import { AvailConnector } from '@paima/providers';
import type { ISubmittableResult } from '@polkadot/types/types';

class AvailBatchedTransactionPoster extends BatchedTransactionPosterBase {
private provider: string;
Expand All @@ -10,25 +13,54 @@ class AvailBatchedTransactionPoster extends BatchedTransactionPosterBase {
this.provider = provider;
}

public override postMessage = async (msg: string): Promise<[number, string]> => {
public override postMessage = async (
msg: string,
hashes: string[]
): Promise<[number, string]> => {
const bytesMsg = new TextEncoder().encode(msg);
const data = base64Encode(bytesMsg);

const req = fetch(`${this.provider}/v2/submit`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
data: data,
}),
})
.then(response => response.json())
.catch(error => console.error(error));
const provider = AvailConnector.instance().getProvider();
if (provider == null) {
throw new Error(`Batcher failed to find Avail JS provider`);
}
const tx = provider.getConnection().api.rpc.tx.dataAvailability.submitData(data);

const receipt = await req;

return [receipt.block_number, receipt.hash];
let sentPosted = false;
const result = await new Promise<[number, string]>((res, rej) =>
tx.signAndSend(provider.getAddress().address, { nonce: -1 }, async result => {
if (result.isError) {
rej(result);
}
if (!sentPosted) {
sentPosted = true;
await this.updateMqttStatus(
hashes,
undefined,
result.txHash.toHex(),
BatcherStatus.Posting
);
}
if (result.isInBlock) {
const signedBlock = await provider
.getConnection()
.api.rpc.derive.chain.getBlock(result.status.asInBlock.toHex());
await this.updateMqttStatus(
hashes,
signedBlock.block.header.number.toNumber(),
result.txHash.toHex(),
BatcherStatus.Finalizing
);
}
if (result.isFinalized) {
const signedBlock = await provider
.getConnection()
.api.rpc.derive.chain.getBlock(result.status.asInBlock.toHex());
res([signedBlock.block.header.number.toNumber(), result.txHash.toHex()]);
}
})
);
return result;
};
}

Expand Down
39 changes: 34 additions & 5 deletions packages/batcher/batcher-transaction-poster/src/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { contractAbis } from '@paima/utils';
import { utf8ToHex } from 'web3-utils';
import { ethers } from 'ethers';
import BatchedTransactionPosterBase from './transactionPoster.js';
import { BatcherStatus } from '@paima/events';

class EvmBatchedTransactionPoster extends BatchedTransactionPosterBase {
private provider: EthersEvmProvider;
Expand Down Expand Up @@ -43,22 +44,50 @@ class EvmBatchedTransactionPoster extends BatchedTransactionPosterBase {
this.provider = newProvider;
};

public override postMessage = async (msg: string): Promise<[number, string]> => {
public override postMessage = async (
msg: string,
hashes: string[]
): Promise<[number, string]> => {
const hexMsg = utf8ToHex(msg);
// todo: unify with buildDirectTx
const iface = new ethers.Interface([
'function paimaSubmitGameInput(bytes calldata data) payable',
]);
const encodedData = iface.encodeFunctionData('paimaSubmitGameInput', [hexMsg]);
const transaction = await this.provider.sendTransaction({

const txRequest = {
data: encodedData,
to: this.contractAddress,
from: this.provider.getAddress().address,
value: '0x' + Number(this.fee).toString(16),
gasLimit: estimateGasLimit(msg.length),
});
const receipt = (await transaction.extra.wait())!;
return [receipt.blockNumber, receipt.hash];
};
const populatedTx = await this.provider.finalizeTransaction(txRequest);
const serializedSignedTx = ethers.Transaction.from(
await this.provider.getConnection().api.signTransaction(populatedTx)
);

const [transaction] = await Promise.all([
this.provider.sendTransaction(txRequest),
...this.updateMqttStatus(
hashes,
undefined,
serializedSignedTx.hash ?? '',
BatcherStatus.Posting
),
]);

const [receipt] = await Promise.all([
transaction.extra.wait(ENV.BATCHER_CONFIRMATIONS),
...this.updateMqttStatus(
hashes,
transaction.extra.blockNumber ?? undefined,
transaction.txHash,
BatcherStatus.Finalizing
),
]);

return [receipt!.blockNumber, receipt!.hash];
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { keepRunning, gameInputValidatorClosed, webserverClosed } from '@paima/batcher-utils';
import { hashBatchSubunit, buildBatchData } from '@paima/concise';
import { wait } from '@paima/utils';
import { BatcherStatus, BuiltinEvents, PaimaEventManager } from '@paima/events';

abstract class BatchedTransactionPosterBase {
private maxSize: number;
Expand Down Expand Up @@ -49,7 +50,7 @@ abstract class BatchedTransactionPosterBase {
}
};

abstract postMessage(_msg: string): Promise<[number, string]>;
abstract postMessage(_msg: string, hashes: string[]): Promise<[number, string]>;

// Returns number of input successfully posted, or a negative number on failure.
private postingRound = async (): Promise<number> => {
Expand All @@ -72,7 +73,7 @@ abstract class BatchedTransactionPosterBase {
let blockHeight: number;
let transactionHash: string;
try {
const postedMessage = await this.postMessage(batchedTransaction);
const postedMessage = await this.postMessage(batchedTransaction, hashes);
blockHeight = postedMessage[0];
transactionHash = postedMessage[1];
console.log('transaction posted at', blockHeight, transactionHash);
Expand Down Expand Up @@ -136,24 +137,40 @@ abstract class BatchedTransactionPosterBase {
blockHeight: number,
transactionHash: string
): Promise<void> => {
for (let hash of hashes) {
try {
await updateStatePosted.run(
{
input_hash: hash,
block_height: blockHeight,
transaction_hash: transactionHash,
},
this.pool
);
} catch (err) {
console.log(
"[batcher-transaction-poster] Error while updating posted inputs' states:",
err
);
throw err;
}
}
await Promise.all([
...this.updateMqttStatus(hashes, blockHeight, transactionHash, BatcherStatus.Finalized),
...hashes
.map(hash => ({
input_hash: hash,
block_height: blockHeight,
transaction_hash: transactionHash,
}))
.map(packagedData =>
updateStatePosted.run(packagedData, this.pool).catch(err => {
console.log(
"[batcher-transaction-poster] Error while updating posted inputs' states:",
err
);
throw err;
})
),
]);
};

protected updateMqttStatus = (
hashes: string[],
blockHeight: undefined | number,
transactionHash: string,
status: BatcherStatus
): Promise<void>[] => {
return hashes.map(hash =>
PaimaEventManager.Instance.sendMessage(BuiltinEvents.BatcherHash, {
batch: hash,
blockHeight,
transactionHash,
status,
})
);
};

private rejectPostedStates = async (hashes: string[]): Promise<void> => {
Expand Down
1 change: 1 addition & 0 deletions packages/batcher/batcher-transaction-poster/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
{ "path": "../../paima-sdk/paima-providers/tsconfig.build.json" },
{ "path": "../../paima-sdk/paima-concise/tsconfig.build.json" },
{ "path": "../../paima-sdk/paima-utils/tsconfig.build.json" },
{ "path": "../../paima-sdk/paima-events/tsconfig.build.json" },
]
}
7 changes: 4 additions & 3 deletions packages/batcher/runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
"prod": "node ./build/index.js"
},
"devDependencies": {
"@types/pg": "^8.10.9",
"@types/express": "^4.17.20"
"@types/express": "^4.17.20",
"@types/pg": "^8.10.9"
},
"dependencies": {
"ethers": "6.11.1",
"express": "^4.18.1",
"pg": "^8.11.3",
"ethers": "6.11.1"
"@paima/broker": "2.4.0"
}
}
Loading