diff --git a/README.md b/README.md index 731466b..aa8bfe3 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,10 @@ This is the LemoChain compatible JavaScript SDK which implements the Generic JSON RPC. -You need to run a local LemoChain node to use this library. +> You need to run a local or remote LemoChain node with flag `--rpc` to use this library. + +[中文版](https://github.com/LemoFoundationLtd/lemo-client/blob/master/README_zh.md) +[English](https://github.com/LemoFoundationLtd/lemo-client/blob/master/README.md) ## Installing @@ -25,7 +28,7 @@ yarn add lemo-client ### As Browser module * Include `lemo-client.min.js` in your html file. -* Use the `LemoClient` object directly from global namespace: +* Use the `LemoClient` object directly from global namespace ## Example @@ -42,63 +45,922 @@ lemo.chain.getBlockByNumber(0) ``` ## LemoChain API -> NOTE: Every API returns a promise, except `watchXXX` which return `watchId` for stop watching +> Almost every API returns a promise object, except `watchXXX`, `stopWatch` and so on +> All API available in the console of LemoChain node. But some APIs are not available over remote connection such as http, websocket -### chain -methods | description | available on http ----|---|--- -lemo.getBlock(number, withTxList) | Get block by height (only stable block) | ✓ -lemo.getBlock(hash, withTxList) | Get block by block hash | ✓ -lemo.getCurrentBlock(false, withTxList) | Get the newest block | ✓ -lemo.getCurrentBlock(true, withTxList) | Get the newest stable block | ✓ -lemo.getCurrentHeight(false) | Get the newest block height | ✓ -lemo.getCurrentHeight(true) | Get the newest stable block height | ✓ -lemo.getGenesis() | Get the first block | ✓ -lemo.getChainID() | Get the chain ID | ✓ -lemo.getGasPriceAdvice() | Get transaction gas price advice | ✓ -lemo.getNodeVersion() | Get the version of LemoChain node | ✓ -lemo.getSdkVersion() | Get the version of lemo-client | ✓ -lemo.watchBlock(withTxList, callback) | Listen for new block | ✓ - -### net -methods | description | available on http ----|---|--- -lemo.net.addPeer(nodeAddr) | Connect to a peer | ✖ -lemo.net.dropPeer(nodeAddr) | Disconnect to a peer | ✖ -lemo.net.getPeers() | Get the connected peer list | ✖ -lemo.net.getPeersCount() | Get the number of connected peers | ✓ -lemo.net.getInfo() | Get the information of current LemoChain node | ✓ - -### mine -methods | description | available on http +API | description | available for remote ---|---|--- -lemo.mine.start() | Start mining | ✖ -lemo.mine.stop() | Stop mining | ✖ -lemo.mine.getMining() | True if current LemoChain node is mining | ✓ -lemo.mine.getLemoBase() | Get the mining benefit account address of current LemoChain node | ✓ +[lemo.getBlock(heightOrHash, withBody)](#submodule-chain-getBlock) | Get block by height or block hash | ✓ +[lemo.getCurrentBlock(stable, withBody)](#submodule-chain-getCurrentBlock) | Get the newest block | ✓ +[lemo.getCurrentHeight(stable)](#submodule-chain-getCurrentHeight) | Get the newest block height | ✓ +[lemo.getGenesis()](#submodule-chain-getGenesis) | Get the first block | ✓ +[lemo.getChainID()](#submodule-chain-getChainID) | Get the chain ID | ✓ +[lemo.getGasPriceAdvice()](#submodule-chain-getGasPriceAdvice) | Get transaction gas price advice | ✓ +[lemo.getNodeVersion()](#submodule-chain-getNodeVersion) | Get the version of LemoChain node | ✓ +[lemo.getSdkVersion()](#submodule-chain-getSdkVersion) | Get the version of lemo-client | ✓ +[lemo.watchBlock(withBody, callback)](#submodule-chain-watchBlock) | Listen for new block | ✓ +[lemo.net.connect(nodeAddr)](#submodule-net-connect) | Connect to a LemoChain node | ✖ +[lemo.net.disconnect(nodeAddr)](#submodule-net-disconnect) | Disconnect to a LemoChain node | ✖ +[lemo.net.getConnections()](#submodule-net-getConnections) | Get the information of connections | ✖ +[lemo.net.getConnectionsCount()](#submodule-net-getConnectionsCount) | Get the count of connections | ✓ +[lemo.net.getInfo()](#submodule-net-getInfo) | Get current node information | ✓ +[lemo.mine.start()](#submodule-mine-start) | Start mining | ✖ +[lemo.mine.stop()](#submodule-mine-stop) | Stop mining | ✖ +[lemo.mine.getMining()](#submodule-mine-getMining) | True if current LemoChain node is mining | ✓ +[lemo.mine.getMiner()](#submodule-mine-getMiner) | Get the mining benefit account address of current LemoChain node | ✓ +[lemo.account.newKeyPair()](#submodule-account-newKeyPair) | Create a private key and account address | ✖ +[lemo.account.getBalance(addr)](#submodule-account-getBalance) | Get the balance of an account | ✓ +[lemo.account.getAccount(addr)](#submodule-account-getAccount) | Get the information of an account | ✓ +[lemo.tx.sendTx(privateKey, txInfo)](#submodule-tx-sendTx) | Sign and send transaction | ✓ +[lemo.tx.sign(privateKey, txInfo)](#submodule-tx-sign) | Sign transaction | ✓ +[lemo.tx.send(signedTxInfo)](#submodule-tx-send) | Send a signed transaction | ✓ +[lemo.tx.watchPendingTx(callback)](#submodule-tx-watchPendingTx) | Listening for new transactions | ✖ +[lemo.stopWatch(watchId)](#submodule-stopWatch) | Stop listening | ✓ +[lemo.isWatching()](#submodule-isWatching) | True if is listening | ✓ + +--- + +### Protocol +Send and receive data by json format, use [JSON-RPC2.0](https://www.jsonrpc.org/specification) standard. +For convenient, all numbers will be convert to string. So the numbers will never overflow. + +#### POST request +``` +{ + "jsonrpc": "2.0", + "method": "chain_getBlockByHeight", + "params": [1, false], + "id": 1 +} +``` +- `jsonrpc` - (string) Always `2.0` +- `method` - (string) API module name and method name connected by `_` +- `params` - (Array) API method parameters, object is available +- `id` - (number) Increasing request id -### account -methods | description | available on http ----|---|--- -lemo.account.newKeyPair() | Create a private key and account address | ✖ -lemo.account.getBalance(addr) | Get the balance of an account | ✓ -lemo.account.getAccount(addr) | Get the information of an account | ✓ +#### Success response +``` +{ + "jsonrpc": "2.0", + "result": {...}, + "id": 1 +} +``` +- `jsonrpc` - (string) Always `2.0` +- `result` - (*) The result could be any type +- `id` - (number) The id in request -### tx -methods | description | available on http ----|---|--- -lemo.tx.sendTx(privateKey, txInfo) | Sign and send transaction | ✓ -lemo.tx.send(signedTxInfo) | Send a signed transaction | ✓ -lemo.tx.sign(privateKey, txInfo) | Sign transaction | ✓ -lemo.tx.watchPendingTx(callback) | Listen for the new Transaction | ✖ +#### Error response +``` +{ + "jsonrpc": "2.0", + "error": {"code": -32601, "message": "Method not found"}, + "id": 1 +} +``` +- `jsonrpc` - (string) Always `2.0` +- `error` - (object) The error detail. It contains a negtive number `code` and a string `message`. +- `id` - (number) The id in request + +--- + +### Data structure + + +#### block +```json +{ + "header": {}, + "transactions": [], + "changeLogs": [], + "confirms": [], + "events": [], + "deputyNodes": [] +} +``` +- `header` The [header](#data-structure-header) of block +- `transactions` All [Transactions](#data-structure-transaction) in block +- `changeLogs` The account data [changeLogs](#data-structure-changeLog) by transactions in block +- `confirms` The [signatures](#data-structure-confirm) from deputies after they verified the block +- `events` The [contract events](#data-structure-event) from transactions in block +- `deputyNodes` New [deputy nodes information](#data-structure-deputyNode) If the block is `snapshot block`, or else it is empty + + +#### header +The header of block +```json +{ + "hash": "0x11d9153b14adb92a14c16b66c3524d62b4742c0e7d375025525e2f131de37a8b", + "height": "0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "miner": "Lemo83GN72GYH2NZ8BA729Z9TCT7KQ5FC3CR6DJG", + "signData": "0x", + "timestamp": "1535630400", + "gasLimit": "105000000", + "gasUsed": "0", + "eventBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "changeLogRoot": "0x93273cebb4f0728991811d5d7c57ae8f88a83524eedb0af48b3061ed2e8017b8", + "deputyRoot": "0x49b613bbdf76be3fe761fd60d1ade6d2835315047c53d6e8199737898b8d9b47", + "eventRoot": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "transactionRoot": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "versionRoot": "0x1e78c4779248d3d8d3cd9b77bf7b67b4c759ec87d45d52a3e79c928290773f4c", + "extraData": "0x" +} +``` +- `hash` Block hash +- `height` Block height +- `parentHash` Previous block hash +- `miner` Address of the account who produce this block +- `signData` Miner's signatue of the block hash +- `timestamp` The time of block creation in seconds +- `gasLimit` Max gas limit for all transactions in block +- `gasUsed` Used gas of all transactions in block +- `eventBloom` The bloom filter for speed up contract events query. Calculated by `events` in block +- `changeLogRoot` The root hash of block's `changeLogs` Merkle Trie +- `deputyRoot` The root hash of block's `deputyNodes` Merkle Trie +- `eventRoot` The root hash of block's `events` Merkle Trie +- `transactionRoot` The root hash of block's `transactions` Merkle Trie +- `versionRoot` The root hash of global `versions` Merkle Patricia Trie. This trie is storing all accounts' newest version +- `extraData` (optional) The custom data from miner + + +#### transaction +Signed transaction +```json +{ + "to": "Lemo83JW7TBPA7P2P6AR9ZC2WCQJYRNHZ4NJD4CY", + "toName": "", + "amount": "100", + "data": "0x", + "expirationTime": "1541566996", + "gasLimit": "2000000", + "gasPrice": "3000000000", + "hash": "0x6d3062a9f5d4400b2002b436bc69485449891c83e23bf9e27229234da5b25dcf", + "message": "", + "r": "0xaf5e573f07e4aaa2932b21b90a4b1b1a317b00a83d66908a0053a337319b149d", + "s": "0x6c1fbad11a56720fe219ef67c0ada27fa3c76212cc849f519e5fbcbe83a88b6b", + "v": "0x20001" +} +``` +- `to` Recipient address +- `toName` (optional) Recipient name. It will be checked with `to` for safe +- `amount` Amount in `mo`. 1`LEMO`=1000000000000000000`mo`=1e18`mo` +- `data` (optional) The extra data. It usually using for calling smart contract. It depends on `type` that how to using this field +- `expirationTime` The expiration time of transaction in seconds. If a transaction's expiration time is more than half hour from now, it may not be packaged in block. It depends on the transactions picking logic from miner +- `gasLimit` Max gas limit of transaction. The transaction will be fail if it cost more gas than gasLimit. And the gas will not be refunded +- `gasPrice` Price of every gas in `mo`. The more gas price the more priority +- `hash` Transaction hash +- `message` (optional) Extra text message from sender +- `r` Signature data +- `s` Signature data +- `v` This field is combined from transaction `type`, `version`(current is 0), `signature recovery data`, `chainID` + +transaction type | description +---|--- +0 | Normal transaction or smart contract execution transaction + +chainID | description +---|--- +1 | LemoChain main net + + +#### changeLog +The modification record of data on chain +```json +{ + "address": "Lemo83GN72GYH2NZ8BA729Z9TCT7KQ5FC3CR6DJG", + "extra": "", + "newValue": "0x8c052b7d2dcc80cd2e40000000", + "type": "BalanceLog", + "version": "1" +} +``` +- `address` The address of account which data is changed +- `version` The version of account data. Every type data has its own version +- Depends on different `type`, the `newValue` and `extra` have different functions + +type | description | newValue | extra +---|---|---|--- +BalanceLog | The change of account balance | New balance | - +StorageLog | The change of storage in contract account | storage value | storage key +CodeLog | Creation of contract account | Contract's code | - +AddEventLog | Creation a contract event | Contract event | - +SuicideLog | Destroying a contract account | - | - + + +#### confirm +The signature of block hash from a deputy node after him verified the block +``` +0x1234 +``` + +#### event +Smart contract event +```json +{ + "address": "Lemo83GN72GYH2NZ8BA729Z9TCT7KQ5FC3CR6DJG" +} +``` -### other -methods | description | available on http ----|---|--- -lemo.stopWatch(watchId) | Stop watching by watch ID | ✓ -lemo.stopWatch() | Stop all watching | ✓ -lemo.isWatching() | True if is watching some data | ✓ + +#### deputyNode +Deputy node information +```json +{ + "ip": "127.0.0.1", + "minerAddress": "Lemo83GN72GYH2NZ8BA729Z9TCT7KQ5FC3CR6DJG", + "nodeID": "0x5e3600755f9b512a65603b38e30885c98cbac70259c3235c9b3f42ee563b480edea351ba0ff5748a638fe0aeff5d845bf37a3b437831871b48fd32f33cd9a3c0", + "port": "7001", + "rank": "0", + "votes": "50000" +} +``` +- `ip` Deputy node ip address +- `minerAddress` The account address to receive mining benefit +- `nodeID` The LemoChain node ID, it is from the public key whose private key is using for sign blocks +- `port` The port to connect other nodes +- `rank` The rank of all deputy nodes +- `votes` The votes count + + +#### account +Account information +```json +{ + "address": "Lemo83GN72GYH2NZ8BA729Z9TCT7KQ5FC3CR6DJG", + "balance": "1599999999999999999999999900", + "records": { + "BalanceLog": { + "version": "3", + "height": "1" + } + }, + "codeHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "root": "0x0000000000000000000000000000000000000000000000000000000000000000" +} +``` +- `address` Account address +- `balance` Account balance. It is a modified `BigNumber` object. It has a method `toMoney()` to output formatted balance +- `records` Modification record object of account. The key is type of [ChangeLog](data-structure-changeLog), value is the newest `ChangeLog`'s version and height of the block which contains this newest `ChangeLog` +- `codeHash` Hash of contract code +- `root` The hash of contranct storage MPT root + +--- + +### Constructor +``` +lemo = new LemoClient({ + host: 'http://127.0.0.1:8001' +}) +``` +- `host` LemoChain node's http listening address. The default value is `http://127.0.0.1:8001` +> NOTE: If the cross domain issue appear. Try to use flag `--rpccorsdomain http://[domain of the web page]:[port]` to restart LemoChain node. + +--- + +### chain API + + +#### lemo.getBlock +``` +lemo.getBlock(heightOrHash [, withBody]) +``` +Get block by height or block hash + +##### Parameters +1. `number|string` - Block height or block hash. If it is block height, only stable blocks will be retrived which confirmed by most deputy nodes +2. `boolean` - (optional) Enable to get block body such as transactions. Default value is `false` + +##### Returns +`Promise` - Call `then` method to get [block](#data-structure-block) object + +##### Example +```js +lemo.getBlock(0).then(function(block) { + console.log(block.header.hash); // "0x11d9153b14adb92a14c16b66c3524d62b4742c0e7d375025525e2f131de37a8b" +}) +``` + +--- + + +#### lemo.getCurrentBlock +``` +lemo.getCurrentBlock([stable [, withBody]]) +``` +Get the newest block + +##### Parameters +1. `boolean` - (optional) If it is true, only stable blocks will be retrived which confirmed by most deputy nodes. Default value is `true` +2. `boolean` - (optional) Enable to get block body such as transactions. Default value is `false` + +##### Returns +`Promise` - Call `then` method to get [block](#data-structure-block) object + +##### Example +```js +lemo.getCurrentBlock(true).then(function(block) { + console.log(block.header.miner); // "Lemo83GN72GYH2NZ8BA729Z9TCT7KQ5FC3CR6DJG" +}) +``` + +--- + + +#### lemo.getCurrentHeight +``` +lemo.getCurrentHeight([stable]) +``` +Get the newest block height + +##### Parameters +1. `boolean` - (optional) If it is true, only stable blocks will be retrived which confirmed by most deputy nodes. Default value is `true` + +##### Returns +`Promise` - Call `then` method to get height string + +##### Example +```js +lemo.getCurrentHeight(true).then(function(height) { + console.log(height); // "100" +}) +``` + +--- + + +#### lemo.getGenesis +``` +lemo.getGenesis() +``` +Get the first block + +##### Parameters +None + +##### Returns +`Promise` - Call `then` method to get [block](#data-structure-block) object + +##### Example +```js +lemo.getGenesis().then(function(height) { + console.log(block.header.parentHash); // "0x0000000000000000000000000000000000000000000000000000000000000000" +}) +``` + +--- + + +#### lemo.getChainID +``` +lemo.getChainID() +``` +Get the chain ID from current connected LemoChain node + +##### Parameters +None + +##### Returns +`Promise` - Call `then` method to get chainID string + +##### Example +```js +lemo.getChainID().then(function(chainID) { + console.log(chainID); // "1" +}) +``` + +--- + + +#### lemo.getGasPriceAdvice +``` +lemo.getGasPriceAdvice() +``` +Get transaction gas price advice + +##### Parameters +None + +##### Returns +`Promise` - Call `then` method to get gas price advice string in uint `mo` + +##### Example +```js +lemo.getGasPriceAdvice().then(function(gasPrice) { + console.log(gasPrice); // "2000000000" +}) +``` + +--- + + +#### lemo.getNodeVersion +``` +lemo.getNodeVersion() +``` +Get the version of LemoChain node + +##### Parameters +None + +##### Returns +`Promise` - Call `then` method to get version string + +##### Example +```js +lemo.getNodeVersion().then(function(version) { + console.log(version); // "1.0.0" +}) +``` + +--- + + +#### lemo.getSdkVersion +``` +lemo.getSdkVersion() +``` +Get the version of lemo-client + +##### Parameters +None + +##### Returns +`Promise` - Call `then` method to get version string + +##### Example +```js +lemo.getSdkVersion().then(function(version) { + console.log(version); // "1.0.0" +}) +``` + +--- + + +#### lemo.watchBlock +``` +lemo.watchBlock(withBody, callback) +``` +Listen for new block. The callback function will be called at the beginning and every times a new stable block produced. + +##### Parameters +1. `boolean` - (optional) Enable to get block body such as transactions. Default value is `false` +2. `Function` - Used to receive [block](#data-structure-block) object + +##### Returns +`number` - watchId for [stop watching](#submodule-stopWatch) + +##### Example +```js +lemo.watchBlock(true, function(block) { + const d = new Date(1000 * parseInt(block.header.timestamp, 10)) + console.log(d.toUTCString()); // "Thu, 30 Aug 2018 12:00:00 GMT" +}) +``` + +--- + +### net API + + +#### lemo.net.connect +``` +lemo.net.connect(nodeAddr) +``` +Connect to a LemoChain node + +##### Parameters +1. `string` - ip address + +##### Returns +`Promise` - No data input in `then` function + +##### Example +```js +lemo.net.connect('127.0.0.1:60002') +``` + +--- + + +#### lemo.net.disconnect +``` +lemo.net.disconnect(nodeAddr) +``` +Disconnect to a LemoChain node + +##### Parameters +1. `string` - ip address + +##### Returns +`Promise` - Call `then` method to get boolean + +##### Example +```js +lemo.net.disconnect('127.0.0.1:60002').then(function(success) { + console.log(sucess ? 'success' : 'fail'); +}) +``` + +--- + + +#### lemo.net.getConnections +``` +lemo.net.getConnections() +``` +Get the information of connections + +##### Parameters +None + +##### Returns +`Promise` - Call `then` method to get connection information list + +##### Example +```js +lemo.net.getConnections().then(function(connections) { + console.log(connections); + // [{ + // localAddress: "127.0.0.1:50825", + // nodeID: "ddb5fc36c415799e4c0cf7046ddde04aad6de8395d777db4f46ebdf258e55ee1d698fdd6f81a950f00b78bb0ea562e4f7de38cb0adf475c5026bb885ce74afb0", + // remoteAddress: "127.0.0.1:60002" + // }] +}) +``` + +--- + + +#### lemo.net.getConnectionsCount +``` +lemo.net.getConnectionsCount() +``` +Get the count of connections + +##### Parameters +None + +##### Returns +`Promise` - Call `then` method to get connection count + +##### Example +```js +lemo.net.getConnectionsCount().then(function(count) { + console.log(count); // "1" +}) +``` + +--- + + +#### lemo.net.getInfo +``` +lemo.net.getInfo() +``` +Get current node information + +##### Parameters +None + +##### Returns +`Promise` - Call `then` method to get node information + +##### Example +```js +lemo.net.getInfo().then(function(info) { + console.log(info.nodeName); // "Lemo" + console.log(info.nodeVersion); // "1.0.0" + console.log(info.os); // "windows-amd64" + console.log(info.port); // "60001" + console.log(info.runtime); // "go1.10.1" +}) +``` + +--- + +### mine API + + +#### lemo.mine.start +``` +lemo.mine.start() +``` +Start mining + +##### Parameters +None + +##### Returns +`Promise` - No data input in `then` function + +##### Example +```js +lemo.mine.start() +``` + +--- + + +#### lemo.mine.stop +``` +lemo.mine.stop() +``` +Stop mining + +##### Parameters +None + +##### Returns +`Promise` - No data input in `then` function + +##### Example +```js +lemo.mine.stop() +``` + +--- + + +#### lemo.mine.getMining +``` +lemo.mine.getMining() +``` +True if current LemoChain node is mining + +##### Parameters +None + +##### Returns +`Promise` - Call `then` method to get boolean + +##### Example +```js +lemo.mine.getMining().then(function(isMining) { + console.log(isMining ? 'mining' : 'not mining'); +}) +``` + +--- + + +#### lemo.mine.getMiner +``` +lemo.mine.getMiner() +``` +Get the account address to receive mining benefit + +##### Parameters +None + +##### Returns +`Promise` - Call `then` method to get account address + +##### Example +```js +lemo.mine.getMiner() + .then(function(miner) { + console.log(miner); // "Lemo83GN72GYH2NZ8BA729Z9TCT7KQ5FC3CR6DJG" + }) +``` + +--- + +### account API + + +#### lemo.account.newKeyPair +``` +lemo.account.newKeyPair() +``` +Create a private key and account address + +##### Parameters +None + +##### Returns +`Promise` - Call `then` method to get account key object + +##### Example +```js +lemo.account.newKeyPair() + .then(function(accountKey) { + console.log(accountKey.private); // "0xfdbd9978910ce9e1ed276a75132aacb0a12e6c517d9bd0311a736c57a228ee52" + console.log(accountKey.address); // "Lemo83BYKZJ4RN4TKC9C78RFW7YHW6S87TPRSH34" + }) +``` + +--- + + +#### lemo.account.getBalance +``` +lemo.account.getBalance(address) +``` +Get the balance of an account + +##### Parameters +1. `string` - account address + +##### Returns +`Promise` - Call `then` method to get balance `BigNumber` object + +##### Example +```js +lemo.account.getBalance('Lemo83BYKZJ4RN4TKC9C78RFW7YHW6S87TPRSH34') + .then(function(balance) { + console.log(balance.toString(10)); // "1600000000000000000000000000" + }) +``` + +--- + + +#### lemo.account.getAccount +``` +lemo.account.getAccount(address) +``` +Get the information of an account + +##### Parameters +1. `string` - account address + +##### Returns +`Promise` - Call `then` method to get [account](#data-structure-account) information + +##### Example +```js +lemo.account.getBalance('Lemo83BYKZJ4RN4TKC9C78RFW7YHW6S87TPRSH34') + .then(function(account) { + console.log(account.balance.toMoney()); // "1600000000 LEMO" + }) +``` + +--- + +### tx API + + +#### lemo.tx.sendTx +``` +lemo.tx.sendTx(privateKey, txInfo) +``` +Sign and send transaction + +##### Parameters +1. `string` - Account private key +2. `object` - Unsigned transaction + - `type` - (number) (optional) Transaction type. Default value is `0` + - `version` - (number) (optional) Transaction encode version. Default value is `0` + - `chainId` - (number) (optional) ChainID of LemoChain. Default value is `1`, it represents main net + - `to` - (string) (optional) Recipient address. Empty `to` represents a contract creation transaction with contract code in `data` field + - `toName` - (string) (optional) Recipient name. It will be checked with `to` for safe + - `amount` - (number|string) (optional) Amount in `mo`. Default value is `0` + - `gasPrice` - (number|string) (optional) Max gas limit of transaction. Default value is `3000000000` + - `gasLimit` - (number|string) (optional) Price of every gas in `mo`. Default value is `2000000` + - `data` - (Buffer|string) (optional) The extra data. It usually be using for calling smart contract + - `expirationTime` - (number) (optional) The expiration time of transaction in seconds. Default is half hour from now + - `message` - (string) (optional) Extra text message from sender + +##### Returns +`Promise` - Call `then` method to get transaction hash + +##### Example +```js +const txInfo = {to: 'Lemo83BYKZJ4RN4TKC9C78RFW7YHW6S87TPRSH34', amount: 100} +lemo.tx.sendTx('0xfdbd9978910ce9e1ed276a75132aacb0a12e6c517d9bd0311a736c57a228ee52', txInfo) + .then(function(txHash) { + console.log(txHash); + }) +``` + +--- + + +#### lemo.tx.sign +``` +lemo.tx.sign(privateKey, txInfo) +``` +Sign transaction and return the signed transaction string +The API is used for implement safety offline transaction: +1. Sign transaction on a offline device +2. Copy the output string ( untamable ) to a online device +3. Call [`lemo.tx.send`](submodule-tx-send) to send the transaction to LemoChain + +##### Parameters +1. `string` - Account private key +2. `object` - Unsigned transaction like the same parameter in [`lemo.tx.sendTx`](submodule-tx-sendTx) + +##### Returns +`Promise` - Call `then` method to get signed [transaction](#data-structure-transaction) information string + +##### Example +```js +const txInfo = {to: 'Lemo83BYKZJ4RN4TKC9C78RFW7YHW6S87TPRSH34', amount: 100} +lemo.tx.sign('0xfdbd9978910ce9e1ed276a75132aacb0a12e6c517d9bd0311a736c57a228ee52', txInfo) + .then(function(signedTx) { + console.log(signedTx); + // {"amount":"100","expirationTime":"1535632200","gasLimit":"2000000","gasPrice":"3000000000","r":"0xdefbd406e0aed8a01ac33877a0267ca720e8231b7660d790386ae45686cf8781","s":"0x3de9fea170ec8fba0cd2574878554558616733c45ea03975bb41104bab3bd312","to":"Lemo83BYKZJ4RN4TKC9C78RFW7YHW6S87TPRSH34","v":"0x030001"} + }) +``` + +--- + + +#### lemo.tx.send +``` +lemo.tx.send(signedTxInfo) +``` +Send a signed transaction + +##### Parameters +1. `object|string` - Signed [transaction](#data-structure-transaction) information. It could be a string which returned by [`lemo.tx.sign`](submodule-tx-sign), as well as an object like the same parameter in [`lemo.tx.sendTx`](submodule-tx-sendTx), but it these fields instead of `type`, `version`, `chainId`: + - `r` - (Buffer|string) Signature data + - `s` - (Buffer|string) Signature data + - `v` - (Buffer|string) This field is combined from transaction `type`, `version`(current is 0), `signature recovery data`, `chainID` + +##### Returns +`Promise` - Call `then` method to get transaction hash + +##### Example +```js +const txInfo = {to: 'Lemo83BYKZJ4RN4TKC9C78RFW7YHW6S87TPRSH34', amount: 100} +lemo.tx.sign('0xfdbd9978910ce9e1ed276a75132aacb0a12e6c517d9bd0311a736c57a228ee52', txInfo) + .then(function(signedTx) { + return lemo.tx.send(signedTx) + }).then(function(txHash) { + console.log(txHash); + }) +``` + +--- + + +#### lemo.tx.watchPendingTx +``` +lemo.tx.watchPendingTx(callback) +``` +Listen for new transactions. The callback function will be called at the beginning and every times new transactions come. (unimplemented in 1.0.0) + +##### Parameters +1. `Function` - Used to receive [transaction](#data-structure-transaction) list + +##### Returns +`number` - WatchId for [stop watching](#submodule-stopWatch) + +##### Example +```js +lemo.watchPendingTx(true, function(transactions) { + console.log(transactions.length); +}) +``` + +--- + +### other API + + +#### lemo.stopWatch +``` +lemo.tx.stopWatch(watchId) +``` +Stop listening + +##### Parameters +1. `number|undefined` - (optional) The id from `lemo.watchXXX`. If is undefined, then stop all watching + +##### Returns +None + +##### Example +```js +lemo.stopWatch() +``` + +--- + + +#### lemo.isWatching +``` +lemo.tx.isWatching() +``` +True if is listening + +##### Parameters +None + +##### Returns +`boolean` - True if is listening + +##### Example +```js +console.log(lemo.isWatching() ? 'watching' : 'not watching') +``` + +--- ## Developing diff --git a/README_zh.md b/README_zh.md index a7ecee9..5d88d4b 100644 --- a/README_zh.md +++ b/README_zh.md @@ -126,8 +126,8 @@ API | 功能 | 可远程使用 ### 数据结构 -#### block +#### block ```json { "header": {}, @@ -145,8 +145,8 @@ API | 功能 | 可远程使用 - `events` 该块中所有交易产生的[合约事件](#data-structure-event)列表 - `deputyNodes` 如果该块是一个`快照块`,则这里保存新一代[共识节点信息](#data-structure-deputyNode)的列表。否则为空 -#### header +#### header 区块头 ```json { @@ -155,7 +155,7 @@ API | 功能 | 可远程使用 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "miner": "Lemo83GN72GYH2NZ8BA729Z9TCT7KQ5FC3CR6DJG", "signData": "0x", - "timestamp": "1535630400" + "timestamp": "1535630400", "gasLimit": "105000000", "gasUsed": "0", "eventBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", @@ -183,8 +183,8 @@ API | 功能 | 可远程使用 - `versionRoot` 该块打包时全局账户版本树的根节点hash - `extraData` (可选) 出块者向区块中添加的自定义信息 -#### transaction +#### transaction 交易 ```json { @@ -223,8 +223,8 @@ chainID | 说明 ---|--- 1 | LemoChain主网 -#### changeLog +#### changeLog 交易对链上数据的修改记录 ```json { @@ -247,25 +247,24 @@ CodeLog | 合约账户创建 | 合约code | - AddEventLog | 产生一条合约日志 | 合约日志 | - SuicideLog | 合约账户销毁 | - | - -#### confirm +#### confirm 共识节点验证区块通过后,对该块hash的签名 ``` 0x1234 ``` -#### event +#### event 合约事件 ```json { - "address": "Lemo83GN72GYH2NZ8BA729Z9TCT7KQ5FC3CR6DJG", - ... + "address": "Lemo83GN72GYH2NZ8BA729Z9TCT7KQ5FC3CR6DJG" } ``` -#### deputyNode +#### deputyNode 共识节点的信息 ```json { @@ -280,12 +279,12 @@ SuicideLog | 合约账户销毁 | - | - - `ip` 节点的ip地址 - `minerAddress` 节点的Lemo收益账号地址 - `nodeID` 节点的ID,即节点对区块签名时的私钥对应的公钥 -- `port` 节点的端口号 +- `port` 与其它节点链接用的端口号 - `rank` 节点的排名 - `votes` 节点的总票数 -#### account +#### account 账户信息 ```json { @@ -293,8 +292,8 @@ SuicideLog | 合约账户销毁 | - | - "balance": "1599999999999999999999999900", "records": { "BalanceLog": { - version: "3", - height: "1" + "version": "3", + "height": "1" } }, "codeHash": "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -315,14 +314,15 @@ lemo = new LemoClient({ host: 'http://127.0.0.1:8001' }) ``` -- `host` LemoChain节点的地址。默认值`http://127.0.0.1:8001` +- `host` LemoChain节点的HTTP连接地址。默认值`http://127.0.0.1:8001` > 注意: 如果连接后出现跨域问题,则需要用参数`--rpccorsdomain http://sdk所在web的域名:端口号`的方式启动LemoChain节点 +--- ### chain模块API -#### lemo.getBlock +#### lemo.getBlock ``` lemo.getBlock(heightOrHash [, withBody]) ``` @@ -344,8 +344,8 @@ lemo.getBlock(0).then(function(block) { --- -#### lemo.getCurrentBlock +#### lemo.getCurrentBlock ``` lemo.getCurrentBlock([stable [, withBody]]) ``` @@ -367,8 +367,8 @@ lemo.getCurrentBlock(true).then(function(block) { --- -#### lemo.getCurrentHeight +#### lemo.getCurrentHeight ``` lemo.getCurrentHeight([stable]) ``` @@ -389,8 +389,8 @@ lemo.getCurrentHeight(true).then(function(height) { --- -#### lemo.getGenesis +#### lemo.getGenesis ``` lemo.getGenesis() ``` @@ -411,8 +411,8 @@ lemo.getGenesis().then(function(height) { --- -#### lemo.getChainID +#### lemo.getChainID ``` lemo.getChainID() ``` @@ -433,8 +433,8 @@ lemo.getChainID().then(function(chainID) { --- -#### lemo.getGasPriceAdvice +#### lemo.getGasPriceAdvice ``` lemo.getGasPriceAdvice() ``` @@ -455,8 +455,8 @@ lemo.getGasPriceAdvice().then(function(gasPrice) { --- -#### lemo.getNodeVersion +#### lemo.getNodeVersion ``` lemo.getNodeVersion() ``` @@ -477,8 +477,8 @@ lemo.getNodeVersion().then(function(version) { --- -#### lemo.getSdkVersion +#### lemo.getSdkVersion ``` lemo.getSdkVersion() ``` @@ -499,8 +499,8 @@ lemo.getSdkVersion().then(function(version) { --- -#### lemo.watchBlock +#### lemo.watchBlock ``` lemo.watchBlock(withBody, callback) ``` @@ -525,8 +525,8 @@ lemo.watchBlock(true, function(block) { ### net模块API -#### lemo.net.connect +#### lemo.net.connect ``` lemo.net.connect(nodeAddr) ``` @@ -545,8 +545,8 @@ lemo.net.connect('127.0.0.1:60002') --- -#### lemo.net.disconnect +#### lemo.net.disconnect ``` lemo.net.disconnect(nodeAddr) ``` @@ -567,8 +567,8 @@ lemo.net.disconnect('127.0.0.1:60002').then(function(success) { --- -#### lemo.net.getConnections +#### lemo.net.getConnections ``` lemo.net.getConnections() ``` @@ -594,8 +594,8 @@ lemo.net.getConnections().then(function(connections) { --- -#### lemo.net.getConnectionsCount +#### lemo.net.getConnectionsCount ``` lemo.net.getConnectionsCount() ``` @@ -616,8 +616,8 @@ lemo.net.getConnectionsCount().then(function(count) { --- -#### lemo.net.getInfo +#### lemo.net.getInfo ``` lemo.net.getInfo() ``` @@ -627,7 +627,7 @@ lemo.net.getInfo() 无 ##### Returns -`Promise` - 通过`then`可以获取到连接数 +`Promise` - 通过`then`可以获取到节点信息 ##### Example ```js @@ -644,8 +644,8 @@ lemo.net.getInfo().then(function(info) { ### mine模块API + #### lemo.mine.start - ``` lemo.mine.start() ``` @@ -664,8 +664,8 @@ lemo.mine.start() --- -#### lemo.mine.stop +#### lemo.mine.stop ``` lemo.mine.stop() ``` @@ -684,8 +684,8 @@ lemo.mine.stop() --- -#### lemo.mine.getMining +#### lemo.mine.getMining ``` lemo.mine.getMining() ``` @@ -706,8 +706,8 @@ lemo.mine.getMining().then(function(isMining) { --- -#### lemo.mine.getMiner +#### lemo.mine.getMiner ``` lemo.mine.getMiner() ``` @@ -731,8 +731,8 @@ lemo.mine.getMiner() ### account模块API -#### lemo.account.newKeyPair +#### lemo.account.newKeyPair ``` lemo.account.newKeyPair() ``` @@ -755,8 +755,8 @@ lemo.account.newKeyPair() --- -#### lemo.account.getBalance +#### lemo.account.getBalance ``` lemo.account.getBalance(address) ``` @@ -778,8 +778,8 @@ lemo.account.getBalance('Lemo83BYKZJ4RN4TKC9C78RFW7YHW6S87TPRSH34') --- -#### lemo.account.getAccount +#### lemo.account.getAccount ``` lemo.account.getAccount(address) ``` @@ -803,8 +803,8 @@ lemo.account.getBalance('Lemo83BYKZJ4RN4TKC9C78RFW7YHW6S87TPRSH34') ### tx模块API -#### lemo.tx.sendTx +#### lemo.tx.sendTx ``` lemo.tx.sendTx(privateKey, txInfo) ``` @@ -812,18 +812,18 @@ lemo.tx.sendTx(privateKey, txInfo) ##### Parameters 1. `string` - 账户私钥 -2. `object` - 签名前的[交易信息](#data-structure-transaction) - - `type` - `{number}` (选填) 交易类型,默认值为0 - - `version` - `{number}` (选填) 交易编码版本号,默认值为0 - - `chainId` - `{number}` (选填) 区块链的chainID,默认值为1,即LemoChain主链 - - `to` - `{string}` (选填) 交易接收者的账户地址。为空表示这是创建智能合约的交易,必须携带`data` - - `toName` - `{string}` (选填) 交易接收者的账户名,会与账户地址进行比对校验。类似银行转账时填写的姓名与卡号的关系 - - `amount` - `{number|string}` (选填) 交易金额,单位`mo`,默认值为0 - - `gasPrice` - `{number|string}` (选填) 交易消耗的gas上限,默认值为3000000000 - - `gasLimit` - `{number|string}` (选填) 交易消耗gas的单价,单位为`mo`,默认值为2000000 - - `data` - `{Buffer|string}` (选填) 交易附带的数据,可用于调用智能合约,默认为空 - - `expirationTime` - `{number}` (选填)交易过期时间戳,单位为秒,默认值为半小时后 - - `message` - `{string}` (选填)交易附带的文本消息,默认为空 +2. `object` - 签名前的交易信息 + - `type` - (number) (选填) 交易类型,默认值为`0` + - `version` - (number) (选填) 交易编码版本号,默认值为`0` + - `chainId` - (number) (选填) 区块链的chainID,默认值为`1`,即LemoChain主链 + - `to` - (string) (选填) 交易接收者的账户地址。为空表示这是创建智能合约的交易,必须携带`data` + - `toName` - (string) (选填) 交易接收者的账户名,会与账户地址进行比对校验。类似银行转账时填写的姓名与卡号的关系 + - `amount` - (number|string) (选填) 交易金额,单位`mo`,默认值为`0` + - `gasPrice` - (number|string) (选填) 交易消耗的gas上限,默认值为`3000000000` + - `gasLimit` - (number|string) (选填) 交易消耗gas的单价,单位为`mo`,默认值为`2000000` + - `data` - (Buffer|string) (选填) 交易附带的数据,可用于调用智能合约,默认为空 + - `expirationTime` - (number) (选填)交易过期时间戳,单位为秒,默认值为半小时后 + - `message` - (string) (选填)交易附带的文本消息,默认为空 ##### Returns `Promise` - 通过`then`可以获取到交易hash @@ -839,19 +839,23 @@ lemo.tx.sendTx('0xfdbd9978910ce9e1ed276a75132aacb0a12e6c517d9bd0311a736c57a228ee --- -#### lemo.tx.sign +#### lemo.tx.sign ``` lemo.tx.sign(privateKey, txInfo) ``` -签名交易并返回出签名后的交易信息字符串。可以在离线电脑上签名,再将签名后的数据拷到联网电脑上,通过[`lemo.tx.send`](submodule-tx-send)方法发送出去 +签名交易并返回出签名后的交易信息字符串 +该方法用于实现安全的离线交易 +1. 在离线电脑上签名 +2. 将签名后的数据拷贝到联网电脑上 +3. 通过[`lemo.tx.send`](submodule-tx-send)方法发送到LemoChain ##### Parameters 1. `string` - 账户私钥 2. `object` - 签名前的交易信息,细节参考[`lemo.tx.sendTx`](submodule-tx-sendTx) ##### Returns -`Promise` - 通过`then`可以获取到签名后的交易信息字符串 +`Promise` - 通过`then`可以获取到签名后的[交易](#data-structure-transaction)信息字符串 ##### Example ```js @@ -865,19 +869,19 @@ lemo.tx.sign('0xfdbd9978910ce9e1ed276a75132aacb0a12e6c517d9bd0311a736c57a228ee52 --- -#### lemo.tx.send +#### lemo.tx.send ``` lemo.tx.send(signedTxInfo) ``` 发送已签名的交易 ##### Parameters -1. `object|string` - 签名后的交易信息,可以是对象形式也可以是[`lemo.tx.sign`](submodule-tx-sign)返回的字符串形式 +1. `object|string` - 签名后的[交易](#data-structure-transaction)信息,可以是对象形式也可以是[`lemo.tx.sign`](submodule-tx-sign)返回的字符串形式 相对于[`lemo.tx.sendTx`](submodule-tx-sendTx)中的交易信息少了`type`、`version`、`chainId`字段,并多出了以下字段 - - `r` - `{Buffer|string}` 交易签名字段 - - `s` - `{Buffer|string}` 交易签名字段 - - `v` - `{Buffer|string}` `type`、`version`、交易签名字段、`chainId`这4个字段组合而成的数据 + - `r` - (Buffer|string) 交易签名字段 + - `s` - (Buffer|string) 交易签名字段 + - `v` - (Buffer|string) `type`、`version`、交易签名字段、`chainId`这4个字段组合而成的数据 ##### Returns `Promise` - 通过`then`可以获取到交易hash @@ -895,8 +899,8 @@ lemo.tx.sign('0xfdbd9978910ce9e1ed276a75132aacb0a12e6c517d9bd0311a736c57a228ee52 --- -#### lemo.tx.watchPendingTx +#### lemo.tx.watchPendingTx ``` lemo.tx.watchPendingTx(callback) ``` @@ -919,8 +923,8 @@ lemo.watchPendingTx(true, function(transactions) { ### 其它API -#### lemo.stopWatch +#### lemo.stopWatch ``` lemo.tx.stopWatch(watchId) ``` @@ -939,8 +943,8 @@ lemo.stopWatch() --- -#### lemo.isWatching +#### lemo.isWatching ``` lemo.tx.isWatching() ```