diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4a0e90e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.git +node_modules +npm-debug diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f9b8fe5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM nervos/godwoken-prebuilds:v0.2.0-rc2 + +WORKDIR "/godwoken-web3" + +RUN apt-get update \ + && apt-get dist-upgrade -y \ + && apt-get install jq -y \ + && apt-get clean \ + && echo "Finished installing dependencies" + +COPY package*.json ./ +COPY packages/godwoken/package*.json ./packages/godwoken/ +COPY packages/api-server/package*.json ./packages/api-server/ +RUN yarn install + +COPY --chown=node . ./ +EXPOSE 8024 + +USER node +CMD ["node", "version"] diff --git a/README.md b/README.md index 4114cfd..e0327f9 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,90 @@ yarn workspace @godwoken-web3/godwoken tsc yarn workspace @godwoken-web3/api-server start ``` -## Web3 RPC +## Web3 RPC Modules + +### net + +- net_version +- net_peerCount +- net_listening + +### web3 + +- web3_sha3 +- web3_clientVersion + +### eth +- eth_chainId +- eth_protocolVersion +- eth_syncing +- eth_coinbase +- eth_mining +- eth_hashrate +- eth_gasPrice +- eth_accounts +- eth_blockNumber +- eth_sign +- eth_signTransaction +- eth_sendTransaction +- eth_getBalance +- eth_getStorageAt +- eth_getTransactionCount +- eth_getCode +- eth_call +- eth_estimateGas +- eth_getBlockByHash +- eth_getBlockByNumber +- eth_getBlockTransactionCountByHash +- eth_getBlockTransactionCountByNumber +- eth_getUncleByBlockHashAndIndex +- eth_getUncleByBlockNumberAndIndex +- eth_getUncleCountByBlockHash +- eth_getCompilers +- eth_getTransactionByHash +- eth_getTransactionByBlockHashAndIndex +- eth_getTransactionByBlockNumberAndIndex +- eth_getTransactionReceipt +- eth_newFilter +- eth_newBlockFilter +- eth_newPendingTransactionFilter +- eth_uninstallFilter +- eth_getFilterLogs +- eth_getFilterChanges +- eth_getLogs +- eth_sendRawTransaction +- eth_getTipNumber +- eth_gw_executeL2Tranaction +- eth_gw_submitL2Transaction +- eth_gw_getAccountIdByScriptHash +- eth_gw_getScriptHashByAccountId +- eth_gw_getNonce +- eth_gw_getTransactionReceipt +- +### gw + +- gw_ping +- gw_get_tip_block_hash +- gw_get_block_hash +- gw_get_block +- gw_get_block_by_number +- gw_get_balance +- gw_get_storage_at +- gw_get_account_id_by_script_hash +- gw_get_nonce +- gw_get_script +- gw_get_script_hash +- gw_get_data +- gw_get_transaction_receipt +- gw_execute_l2transaction +- gw_execute_raw_l2transaction +- gw_submit_l2transaction +- gw_submit_withdrawal_request + +### poly +- poly_ethAddressToPolyjuiceAddress +- poly_polyjuiceAddressToEthAddress +## Examples ### web3_clientVersion ``` @@ -208,3 +291,35 @@ curl http://localhost:3000 -X POST -H "Content-Type: application/json" -d '{"jso // Response {"jsonrpc":"2.0","id":1,"result":"eth_sign is not supported!"} ``` + +### gw_get_script_hash + +``` +// Request +curl http://localhost:3000 -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method":"gw_get_script_hash", "params": ["0x0"], "id": 1}' + +// Response +{"jsonrpc":"2.0","id":1,"result":"0xdb5b85ffffb98bb103a8763a6be8c02d8442f232061e1e644b25beba4b1693c1"} + +``` + +### gw_get_script + +``` +// Request +curl http://localhost:3000 -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method":"gw_get_script", "params": ["0xdb5b85ffffb98bb103a8763a6be8c02d8442f232061e1e644b25beba4b1693c1"], "id": 1}' + +// Response +{"jsonrpc":"2.0","id":1,"result":{"code_hash":"0x841f75a94dbac1b2b400f29d55c02e5535e8ccca38e26c4245022f31f3ff2e81","hash_type":"type","args":"0x599950fbd06d2592d2903633c740f2ad9578ab7aee45d6d0d9f0c07f093417a6"}} + +``` + +### gw_get_nonce +``` +// Request +curl http://localhost:3000 -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method":"gw_get_nonce", "params": ["0x2"], "id": 1}' + +// Response +{"jsonrpc":"2.0","id":1,"result":"0x1"} + +``` \ No newline at end of file diff --git a/packages/api-server/app.js b/packages/api-server/app.js index 5aca783..ea587d8 100644 --- a/packages/api-server/app.js +++ b/packages/api-server/app.js @@ -27,11 +27,17 @@ app.use(function (req, res, next) { // error handler app.use(function (err, req, res, next) { + console.error(err.stack); + // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page + console.error("err.status:", err.status); + if (res.headersSent) { + return next(err) + } res.status(err.status || 500); res.render('error'); }); diff --git a/packages/api-server/src/convert-tx.ts b/packages/api-server/src/convert-tx.ts index 8148c1b..a92cc5a 100644 --- a/packages/api-server/src/convert-tx.ts +++ b/packages/api-server/src/convert-tx.ts @@ -46,6 +46,12 @@ function debugLogger(...messages: any[]) { } } +export function calcEthTxHash(encodedSignedTx: HexString): Hash { + const ethTxHash = + '0x' + keccak256(Buffer.from(encodedSignedTx.slice(2), 'hex')).toString('hex'); + return ethTxHash +} + export async function generateRawTransaction( data: HexString, rpc: RPC @@ -53,7 +59,7 @@ export async function generateRawTransaction( debugLogger('origin data:', data); const polyjuiceTx: PolyjuiceTransaction = decodeRawTransactionData(data); debugLogger('decoded polyjuice tx:', polyjuiceTx); - const godwokenTx = parseRawTransactionData(polyjuiceTx, rpc); + const godwokenTx = await parseRawTransactionData(polyjuiceTx, rpc); return godwokenTx; } diff --git a/packages/api-server/src/methods/modules/eth.ts b/packages/api-server/src/methods/modules/eth.ts index e999719..d65ddcd 100644 --- a/packages/api-server/src/methods/modules/eth.ts +++ b/packages/api-server/src/methods/modules/eth.ts @@ -17,8 +17,10 @@ import { camelToSnake, toHex, handleBlockParamter } from '../../util'; import { core, utils, HexNumber, Hash } from '@ckb-lumos/base'; import { normalizers, Reader } from 'ckb-js-toolkit'; import { types, schemas } from '@godwoken-web3/godwoken'; -import { generateRawTransaction } from '../../convert-tx'; +import { calcEthTxHash, generateRawTransaction } from '../../convert-tx'; import { Script } from '@ckb-lumos/base'; +import { INVALID_PARAMS } from '../error-code'; + const Config = require('../../../config/eth.json'); const blake2b = require('blake2b'); require('dotenv').config({ path: './.env' }); @@ -125,6 +127,12 @@ export class Eth { validators.newFilterParams ]); + this.sendRawTransaction = middleware( + this.sendRawTransaction.bind(this), + 1, + [validators.hexString] + ); + // this.syncing = middleware(this.syncing.bind(this), 0); @@ -814,14 +822,22 @@ export class Eth { } async sendRawTransaction(args: [string], callback: Callback) { - const data = args[0]; - const rawTx = await generateRawTransaction(data, this.rpc); - const moleculeTx = new Reader( - schemas.SerializeL2Transaction(types.NormalizeL2Transaction(rawTx)) - ).serializeJson(); - const result = await this.rpc.submit_l2transaction(moleculeTx); - console.log('sendRawTransaction hash:', result); - callback(null, result); + try { + const data = args[0]; + const rawTx = await generateRawTransaction(data, this.rpc); + const moleculeTx = new Reader( + schemas.SerializeL2Transaction(types.NormalizeL2Transaction(rawTx)) + ).serializeJson(); + const gwTxHash = await this.rpc.submit_l2transaction(moleculeTx); + console.log('sendRawTransaction gw hash:', gwTxHash); + const ethTxHash = calcEthTxHash(data); + console.log("sendRawTransaction eth hash:", ethTxHash); + callback(null, ethTxHash); + } catch (error) { + console.error(error); + return callback({ code: INVALID_PARAMS, message: error.message }); + // https://www.jsonrpc.org/specification | 5.1 Error object + } } /* #endregion */ diff --git a/packages/api-server/src/methods/types.ts b/packages/api-server/src/methods/types.ts index ef77342..8bf8124 100644 --- a/packages/api-server/src/methods/types.ts +++ b/packages/api-server/src/methods/types.ts @@ -1,5 +1,6 @@ import { HexNumber, HexString } from '@ckb-lumos/base'; export type Error = { + code?: number; message: string; } | null;