Introduction
QuarkChain is an innovative permissionless blockchain architecture that aims to provide a secure, decentralized, and scalable blockchain solution to deliver 100,000+ on-chain TPS.
QuarkChain fully supports Ethereum smart contract enabling developers to write and debug smart contract quickly using popular tools like remix and build scalable DApps that will be free from network congestion. As you may know, CryptoKitties, one of the most popular blockchain games, severely slowed down the transactions on Ethereum in Dec 2017 and resulted in network congestion for weeks. It shows the importance of scalability issues.
QuarkChain has launched a public testnet with 6450 nodes and 256 shards and presented a live demo of 10K+ TPS which is about 500X Ethereum’s throughput in 2018, and the mainnet has launched on 4/30, 2019.
The main features of QuarkChain include:
- Reshardable two-layered blockchain: QuarkChain consists of two layers of blockchains. We apply elastic sharding blockchains (shards) as the first layer, and a root blockchain as the second layer that confirms the blocks from the first layer. The first layer is flexible to be resharded as needed without changing the root layer.
- Guaranteed security by market-driven collaborative mining: To ensure the security of all transactions, a game-theoretic framework is designed for incentives, where at least 50% of overall hash powers are allocated to the root chain to prevent double spending attack on any transactions.
- Anti-centralized horizontal scalability: In any blockchain network with a high TPS, a super-full node can be extremely expensive, which encourages centralization. In contrast, QuarkChain allows multiple cheap nodes forming a cluster to replace a super-full node.
- Efficient cross-shard transactions: Cross-shard transactions in QuarkChain can be issued at any time, and confirmed in minutes. The speed of cross-shard transactions increases linearly as the number of shards increases.
- Ethereum smart contract support: QuarkChain adopts Ethereum Virtual Machine allowing developers to easily migrate the existing ethereum smart contracts and benefit from the high throughput of QuarkChain.
Basic Concepts
Address
A QuarkChain address consists of a normal 20-byte Ethereum address (which is called the recipient of a QuarkChain address) and a 4-byte full shard key.
To better support re-sharding and dynamic updates without affecting existing shards, we proposed a middle layer abstraction between the whole network and the underlying shards, which is called, well, chains: a QuarkChain network, contains multiple chains, where each chain contains multiple shards. Note that a chain is merely a conceptual layer, all the consensus logic (e.g. root-chain-first-consensus, or cross-shard transaction implementation) still apply to all the shards.
For example, the following is a QuarkChain address.
To find the chain an address belongs to, we use the following function
And to find the shard an address belongs to, use the following function
Now the 4-byte full shard ID is encoded as following (using 0x0001000f
as an example):
- Use first two bytes to denote chain ID. In the example the chain ID is 1 (
0x0001
) - The remaining two bytes follow the same encoding as before. Assume chain 1 has 8 shards,
0x000f
corresponds to shard 7 becauseSHARD_ID = FULL_SHARD_ID & (SHARD_SIZE - 1)
Therefore 0x0001000f
should be interpreted as chain 1 shard 7.
With the same formula you can build addresses of the same recipient for different shards. This will allow a single recipient to receive QKC in any shard.
QuarkChain network consists of a certain number of chains and each chain has a certain number of shards (SHARD_SIZE
) which is always a power of 2.
Another common value returned in JSON RPC is called branch, which is simply a wrapper over aforementioned ID encoding, also it's used interchangeably with fullShardId
Note SHARD_SIZE
is encoded in the latter 2 bytes as the most significant bit.
Also, addresses used in an EVM smart contract are still 20 bytes (the recipient in QuarkChain) as the execution scope of a smart contract cannot go beyond the shard it belongs to.
For a more detailed comparison between full shard keys v.s. full shard IDs (or branches), take a look at this GitHub issue.
Transaction
These are the fields for a transaction:
fields = [
("nonce", big_endian_int),
("gasprice", big_endian_int),
("startgas", big_endian_int),
("to", utils.address),
("value", big_endian_int),
("data", binary),
("network_id", big_endian_int),
("from_full_shard_key", BigEndianInt(4)),
("to_full_shard_key", BigEndianInt(4)),
("gas_token_id", big_endian_int),
("transfer_token_id", big_endian_int),
("version", big_endian_int),
("v", big_endian_int),
("r", big_endian_int),
("s", big_endian_int),
]
To the right is the Python definition of a transaction in Quarkchain.
Six fields are added onto the existing Ethereum transaction data structure.
Field | Type | Description |
---|---|---|
from_full_shard_key |
4 bytes fixed int | Identifies the source chain/shard of the transaction |
to_full_shard_key |
4 bytes fixed int | Identifies the destination chain/shard of the transaction |
network_id |
int | identifies the network e.g. devnet, mainnet (similar to ethereum's chain id which is hacked into the 'v' field) |
version |
int | identifies the signature style; 0: eth-style signature; 1: typed signature (EIP-712) as implemented by MetaMask before #4803; 2: typed signature (EIP-155) |
gas_token_id |
int | id of a native token |
transfer_token_id |
int | id of a native token |
Note that when constructing a transaction, from_full_shard_key
should be the last 4 bytes of the sender's address, to should be the recipient of the receiver’s address, i.e., first 20 bytes from receiver's address, and to_full_shard_key
should be the full shard key, i.e., last 4 bytes of the receiver's address. network_id
should be 255 for current beta version of devnet, or 1 for the mainnet.
On native token, the current mainnet only supports QKC token (ID: 35760 or "0x8bb0"). For the rationale of multi-native-token design, please check out this article.
Transaction Id and Block Id
In QuarkChain we use transaction id and block id to identify transaction and block rather than the transaction hash and block hash used in Ethereum. The id is simply the hash with a full shard key appended so that the object can be looked up directly from the chain/shard.
Root block id is equal to its hash as it does not belong to any chain/shard.
Minor block refers to the block on each chain/shard.
Smart Contracts
QuarkChain runs EVM on each chain/shard and thus supports all Ethereum smart contract bytecode compiled from Solidity.
Deployment
A smart contract is always deployed to a specific chain/shard decided by toFullShardKey
in the transaction. Similar to Ethereum, leave the to field empty and put the byte code in the data field.
fromFullShardKey
and toFullShardKey
must map to the same chain/shard in order to succeed, i.e., the same chain/shard id according to Eq. (1). The fullShardKey
of the contract address created will be the same as toFullShardKey
. Normally you should just set toFullShardKey
the same as fromFullShardKey
.
A couple of comments on smart contract deployment:
- If a user does not have any balance on the shard where the contract is to be deployed, a user must manually get sufficient balance from either 1) user’s balance of another shard via cross-shard transaction or 2) another user's balance. In the future, case 1) will be automatically handled by a smart wallet.
- If a smart contract calls another smart contract in the shard, both caller and callee smart contracts must have the same full shard key. Otherwise, such call will fail. This guarantees that both smart contracts will always be in the same shard no matter how the network is resharded (not enforced yet in the devnet).
Calling a Smart Contract
Calling a smart contract is simliar to Ethereum -- you can either use the UI on the blockchain explorer and load the ABI, or you can use a library like web3 that handles the interfacing for you. As a note, fromFullShardKey
and toFullShardKey
must map to the same chain/shard in order for the call to succeed. Otherwise gas will be consumed but the contract will not be called.
Tutorial
Support for DApp development is still at early stage though we aim at providing the same level of development experience as Ethereum eventually. This tutorial assumes readers have basic knowledge of Ethereum smart contract development and thus it focuses on the contract deployment and invocation on QuarkChain network. Also please read the Basic Concepts before proceeding with the tutorial.
MetaMask
QuarkChain supports using MetaMask to perform non-cross-chain operations (such as transfers, contract calls), the usage is same as Ethereum. The following table is the configuration of MetaMask for mainnet and devnet.
Network Name | RPC URL | Chain ID | Currency Symbol | Block Explorer URL |
---|---|---|---|---|
Quarkchain S0 |
http://eth-jrpc.mainnet.quarkchain.io:39000 | 100001 | QKC | https://mainnet.quarkchain.io/0 |
Quarkchain S1 |
http://eth-jrpc.mainnet.quarkchain.io:39001 | 100002 | QKC | https://mainnet.quarkchain.io/1 |
Quarkchain S2 |
http://eth-jrpc.mainnet.quarkchain.io:39002 | 100003 | QKC | https://mainnet.quarkchain.io/2 |
Quarkchain S3 |
http://eth-jrpc.mainnet.quarkchain.io:39003 | 100004 | QKC | https://mainnet.quarkchain.io/3 |
Quarkchain S4 |
http://eth-jrpc.mainnet.quarkchain.io:39004 | 100005 | QKC | https://mainnet.quarkchain.io/4 |
Quarkchain S5 |
http://eth-jrpc.mainnet.quarkchain.io:39005 | 100006 | QKC | https://mainnet.quarkchain.io/5 |
Quarkchain S6 |
http://eth-jrpc.mainnet.quarkchain.io:39006 | 100007 | QKC | https://mainnet.quarkchain.io/6 |
Quarkchain S7 |
http://eth-jrpc.mainnet.quarkchain.io:39007 | 100008 | QKC | https://mainnet.quarkchain.io/7 |
Network Name | RPC URL | Chain ID | Currency Symbol | Block Explorer URL |
---|---|---|---|---|
Quarkchain Dev S0 |
http://eth-jrpc.devnet.quarkchain.io:39900 | 110001 | QKC | https://devnet.quarkchain.io/0 |
Quarkchain Dev S1 |
http://eth-jrpc.devnet.quarkchain.io:39901 | 110002 | QKC | https://devnet.quarkchain.io/1 |
Quarkchain Dev S2 |
http://eth-jrpc.devnet.quarkchain.io:39902 | 110003 | QKC | https://devnet.quarkchain.io/2 |
Quarkchain Dev S3 |
http://eth-jrpc.devnet.quarkchain.io:39903 | 110004 | QKC | https://devnet.quarkchain.io/3 |
Quarkchain Dev S4 |
http://eth-jrpc.devnet.quarkchain.io:39904 | 110005 | QKC | https://devnet.quarkchain.io/4 |
Quarkchain Dev S5 |
http://eth-jrpc.devnet.quarkchain.io:39905 | 110006 | QKC | https://devnet.quarkchain.io/5 |
Quarkchain Dev S6 |
http://eth-jrpc.devnet.quarkchain.io:39906 | 110007 | QKC | https://devnet.quarkchain.io/6 |
Quarkchain Dev S7 |
http://eth-jrpc.devnet.quarkchain.io:39907 | 110008 | QKC | https://devnet.quarkchain.io/7 |
Quarkchain + Web3.js
QuarkChain’s client library quarkchain-web3.js is built around web3.js which is the Javascript-based client library for Ethereum. Please visit the quarkchain-web3.js github repo for the API and examples. MetaMask is required to manage accounts and sign transactions if you are using quarkchain-web3.js. Follow the steps below to try it out, or you can navigate to the API Access section for more direct usage.
The below Javascript will retrieve your QKC balance:
QuarkChain.injectWeb3(web3, "http://jrpc.devnet.quarkchain.io:38391");
var ethAddr = web3.eth.accounts[0]; // current ETH account in MetaMask
var qkcAddr = QuarkChain.getQkcAddressFromEthAddress(ethAddr);
web3.qkc.getBalance(qkcAddr).toString(10); // balance in wei
1. Install MetaMask and create an account.
2. Visit http://devnet.quarkchain.io/wallet and verify your MetaMask account is shown on the page
3. Open the browser console where web3 is automatically injected by MetaMask
4. Run the Javascript command to verify everything has been set up correctly (ping us on Telegram if you need devnet tokens)
Create wallet
Disable MetaMask and navigate to https://devnet.quarkchain.io/wallet to get a new address. Copy-paste the private key somewhere for signing transactions and recover the address later.
Send Transaction
Below you will find the Javascript code change to ethereumjs-tx that we use in our devnet frontend.
var fields = [{
name: 'nonce',
length: 32,
allowLess: true,
default: new Buffer([])
}, {
name: 'gasPrice',
length: 32,
allowLess: true,
default: new Buffer([])
}, {
name: 'gasLimit',
alias: 'gas',
length: 32,
allowLess: true,
default: new Buffer([])
}, {
name: 'to',
allowZero: true,
length: 20,
default: new Buffer([])
}, {
name: 'value',
length: 32,
allowLess: true,
default: new Buffer([])
}, {
name: 'data',
alias: 'input',
allowZero: true,
default: new Buffer([])
}, {
name: 'networkId',
length: 32,
allowLess: true,
default: new Buffer([])
}, {
name: 'fromFullShardKey',
length: 4,
}, {
name: 'toFullShardKey',
length: 4,
}, {
name: 'gasTokenId',
length: 8,
allowLess: true,
default: new Buffer([])
}, {
name: 'transferTokenId',
length: 8,
allowLess: true,
default: new Buffer([])
}, {
name: 'version',
length: 32,
allowLess: true,
default: new Buffer([])
}, {
name: 'v',
allowZero: true,
default: new Buffer([])
}, {
name: 'r',
length: 32,
allowZero: true,
allowLess: true,
default: new Buffer([])
}, {
name: 's',
length: 32,
allowZero: true,
allowLess: true,
default: new Buffer([])
}];
Both contract deployment and invocation are performed through sending specially crafted transactions to the QuarkChain network through JSON RPC sendRawTransaction which accepts a serialized transaction object in RLP. Existing Ethereum libraries (e.g., ethereumjs-tx) can be used to create, sign, and serialize transaction objects. However, small changes are required to accommodate addtional fields added specifically for QuarkChain. An alternative is using sendTransaction endpoint by directly passing the transaction data as a JSON object, which requires the caller to have the signatures ready (v
, r
, and s
).
With the above changes we can use the following Javascript code to build a transaction, sign the transaction, and send it to the QuarkChain devnet API.
const txParams = {
nonce: '0x00',
gasPrice: '0x09184e72a000',
gasLimit: '0x2710',
to: '0x1234567890123456789012345678901234567890', // recipient of to address
value: '0x12',
data: '0x7f746573743',
fromFullShardKey: '0x12345678',
toFullShardKey: '0x12345678',
networkId: '0x1',
gasTokenId: '0x8bb0',
transferTokenId: '0x8bb0'
}
const tx = new ethereumjs.Tx(txParams)
const key = '0x...'
tx.sign(ethereumjs.Util.toBuffer(key))
const rawTx = "0x" + tx.serialize().toString("hex")
// Send raw transaction through the devnet web server
try {
var txResp = await axios.post("https://devnet.quarkchain.io/sendRawTx", {
rawTx: rawTx,
});
// To check transaction status use this id to call getTransactionReceipt
const txId = txResp.data.txId;
} catch (error) {
console.log("Sending transaction failed");
}
Contract Deployment
We have three ways to deploy contracts. 1. Deploy the contract through Remix and use MetaMask to point to the shard.
Go to https://devnet.quarkchain.io/contract and deploy the contract through the UI. On the transaction status page you may find the contract address once the transaction is confirmed.
Send a transaction with 'to' left empty, toFullShardKey set to the same value as fromFullShardKey, data filled with the bytecode in hex. Once the transaction is confirmed call getTransactionReceipt with the transaction id to retrieve the contract address.
Note: the bytecode of the contract you use to deploy can be obtained through a tool like Remix.
Contract Invocation
Calling via the devnet API endpoint
try {
var txResp = await axios.post("https://devnet.quarkchain.io/call", {
rawTx: rawTx,
});
console.log(txResp);
} catch (error) {
console.log("Call failed");
}
Read
To read data from the contract without modifying the state on the blockchain, create a transaction with the contract function or variable encoded into the data
field and use the JSON RPC call interface to retrieve the results. Ethereumjs-abi or other similar libraries can be used to handle encoding.
Write
Similar to read but use sendRawTransaction instead of call to submit the transaction. Like previous example check transaction status through getTransactionReceipt.
JSON RPC
QuarkChain JSON RPC shares the similar interfaces with Ethereum and follows the same HEX value encoding. The most notable difference is the chain/shard id in certain APIs.
The RPCs run on HTTP. All the operations are performed on the lastest blocks.
networkInfo
curl -X POST --data '{
"jsonrpc": "2.0",
"method": "networkInfo",
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": {
"networkId": "0x1",
"chainSize": "0x8",
"shardSizes": ["0x1", "0x1", "0x1", "0x1", "0x1", "0x1", "0x1", "0x1"],
"syncing": false,
"mining": false,
"shardServerCount": 4
},
"id": 1
}
Param Name | Type | Description |
---|---|---|
- | N/A | N/A |
Return Value | Type | Description |
---|---|---|
networkId |
QUANTITY | integer of the network id |
chainSize |
QUANTITY | integer of the current number of chains in the network |
shardSizes |
QUANTITY | integer of the current number of shards by chain in the network |
shardServerCount |
QUANTITY | |
syncing |
BOOL | whether the cluster is syncing (depends on which cluster the API connects to) |
mining |
BOOL | whether is mining locally |
getTransactionCount
curl -X POST --data '{
"jsonrpc": "2.0",
"method": "getTransactionCount",
"params": ["0x04E823bfD0EE5a05f072C346282e252e15CCa98D0003c32E"],
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": "0x0",
"id": 1
}
Returns the number of transactions sent from an address. Similar to Ethereum, the transaction count is guaranteed to be non-decreasing.
Param Name | Type | Description |
---|---|---|
-- | DATA, 24 bytes | address you want balance of |
Return Value | Type | Description |
---|---|---|
-- | QUANTITY | number of transactions sent from the address |
getBalances
curl -X POST --data '{
"jsonrpc": "2.0",
"method": "getBalances",
"params": ["0x04E823bfD0EE5a05f072C346282e252e15CCa98D0006C32E"],
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": {
"branch": "0x60001",
"fullShardId": "0x60001",
"shardId": "0x0",
"chainId": "0x6",
"balances": [{
"tokenId": "0x3de",
"tokenStr": "QI",
"balance": "0x19c00f6b4cbcc00000"
}, {
"tokenId": "0x8bb0",
"tokenStr": "QKC",
"balance": "0x246fb022c10140f000"
}]
},
"id": 1
}
Returns the balances of the account of given address including native token balances.
Param Name | Type | Description |
---|---|---|
-- | DATA, 24 bytes | address you want balance of |
Return Value | Type | Description |
---|---|---|
balances | JSON array | list of tokens' balance object in wei |
getAccountData
curl -X POST --data '{
"jsonrpc": "2.0",
"method": "getAccountData",
"params": ["0x04E823bfD0EE5a05f072C346282e252e15CCa98D0003c32E", "latest", true],
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": {
"primary": {
"fullShardId": "0x30001",
"shardId": "0x0",
"chainId": "0x3",
"balances": [],
"transactionCount": "0x0",
"isContract": false
},
"shards": [{
"fullShardId": "0x1",
"shardId": "0x0",
"chainId": "0x0",
"balances": [],
"transactionCount": "0x0",
"isContract": false
}, {
"fullShardId": "0x40001",
"shardId": "0x0",
"chainId": "0x4",
"balances": [],
"transactionCount": "0x0",
"isContract": false
}, {
"fullShardId": "0x10001",
"shardId": "0x0",
"chainId": "0x1",
"balances": [],
"transactionCount": "0x0",
"isContract": false
}, {
"fullShardId": "0x50001",
"shardId": "0x0",
"chainId": "0x5",
"balances": [],
"transactionCount": "0x0",
"isContract": false
}, {
"fullShardId": "0x20001",
"shardId": "0x0",
"chainId": "0x2",
"balances": [],
"transactionCount": "0x0",
"isContract": false
}, {
"fullShardId": "0x60001",
"shardId": "0x0",
"chainId": "0x6",
"balances": [{
"tokenId": "0x8bb0",
"tokenStr": "QKC",
"balance": "0x8ac7230489e80000"
}],
"transactionCount": "0x0",
"isContract": false
}, {
"fullShardId": "0x30001",
"shardId": "0x0",
"chainId": "0x3",
"balances": [],
"transactionCount": "0x0",
"isContract": false
}, {
"fullShardId": "0x70001",
"shardId": "0x0",
"chainId": "0x7",
"balances": [],
"transactionCount": "0x0",
"isContract": false
}]
},
"id": 1
}
Aggregates account data including both primary and secondary addresses (i.e. addresses in other shards).
Param Name | Type | Description |
---|---|---|
-- | DATA, 24 bytes | |
-- | STRING | The latest block (current head of the blockchain) |
-- | BOOL | true to include data from other shards, otherwise false |
Return Value | Type | Description |
---|---|---|
primary |
JSON object | account data from primary shard |
shards |
JSON array | list of account datas from secondary (other) shards |
shardId |
QUANTITY | integer of the shard id |
chainId |
QUANTITY | integer of the chain id |
balances |
QUANTITY | list of native token balances |
tokenId |
QUANTITY | numerical ID of the native token |
tokenStr |
STRING | symbol of the native token |
balance |
QUANTITY | native token balance |
transactionCount |
QUANTITY | number of transactions sent from address |
isContract |
BOOL | whether the current chain/shard is a smart contract address |
sendTransaction
curl -X POST --data '{
"jsonrpc": "2.0",
"method": "sendTransaction",
"params": {
"nonce": "0x4",
"gasPrice": "0x2540be400", // 10 Gwei
"gas": "0x7530", // 30000
"value": "0xde0b6b3a7640000", // 1 QKC
"data": "0x",
"fromFullShardKey": "0x19e189ec",
"toFullShardKey": "0x18f9ba2c",
"networkId": "0x3",
"to": "0x283B50c1326F5C09BA792cc0Ad6C08b5035a36711",
"v": "0x1a",
"r": "0x293d59ef8705e34585d646f5899530d52a2d39b312fd061607036152e5fcf589",
"s": "0x98d2e479720cee2be165703dd97085765adc65b18ed8d9dfbf3d6d7e7fe5a6e",
"gasTokenId":"0x8bb0",
"transferTokenId":"0x8bb0"
},
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": "0xa786dc17bf8b302d8678666e5f97290c6467c4302a0a1402cb7693267152402519e189ec",
"id": 1
}
Creates a new message call transaction or a contract creation, if the data field contains code. Note the transaction needs to be signed by the client (for example, ethereumjs-tx).
Param Name | Type | Description |
---|---|---|
nonce |
QUANTITY | (optional) integer of a nonce, for overriding your pending transactions that use the same nonce |
gasPrice |
QUANTITY | integer of the gas price used for each paid gas |
gas |
QUANTITY | integer of the gas provided for the transaction execution |
value |
QUANTITY | (optional) integer of the value sent with this transaction |
data |
DATA | compiled code of a contract, OR, the hash of the invoked method signature with encoded parameters |
fromFullShardKey |
QUANTITY, 4 bytes | integer of the full shard key for sending address, see Address for more info |
toFullShardKey |
QUANTITY, 4 bytes | integer of the full shard key for receiving address |
networkId |
QUANTITY | integer of the id of the network (e.g. devnet, mainnet) |
to |
DATA, 20 bytes | recipient's address, that does NOT include the full shard key |
v |
QUANTITY | ECDSA recovery id |
r |
DATA, 32 bytes | ECDSA signature r |
s |
DATA, 32 bytes | ECDSA signature s |
gasTokenId |
QUANTITY | integer of the id of the native token for gas |
transferTokenId |
QUANTITY | integer of the id of the native token to transfer |
Notes:
- The
to
parameter is not the full QuarkChain address, but rather, the first 20 bytes of the address (equivalent to Ethereum's addresses). Remember, the last 4 bytes encode thefullShardKey
which is passed as a parameter in this case. - We assume you always have the private key for the account, so after signing the transaction you need to include v, r and s fields as hex strings
Return Value | Type | Description |
---|---|---|
-- | DATA, 36 bytes | the transaction id or null on failure |
sendRawTransaction
curl -X POST --data '{
"jsonrpc": "2.0",
"method": "sendRawTransaction",
"params": ["0xf87f0b8502540be40082520894d0bb6e0ed6c2e083274af28baa62d0953e4cfb28888ac7230489e800008081ff840000c32e840000f295828bb0828bb0801ba0e838ced32695d6196feae149db2502adadb19ab24ff0e3ea974b967282757f59a06c8d88598eece0d8be3eaf99185d26755c77f8372b129c920eb4a32183643e9b"],
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": "0x78b8706047e04a34158f2775409733e2c984638e106e07709489d501722a53120000c32e",
"id": 1
}
Creates new message call transaction or a contract creation for signed transactions.
Param Name | Type | Description |
---|---|---|
-- | DATA | signed transaction data |
Return Value | Type | Description |
---|---|---|
-- | DATA, 36 bytes | the transaction id or null on failure |
getTransactionById
curl -X POST --data '{
"jsonrpc": "2.0",
"method": "getTransactionById",
"params": ["0x78b8706047e04a34158f2775409733e2c984638e106e07709489d501722a53120000c32e"],
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": {
"id": "0x78b8706047e04a34158f2775409733e2c984638e106e07709489d501722a53120000c32e",
"hash": "0x78b8706047e04a34158f2775409733e2c984638e106e07709489d501722a5312",
"nonce": "0xb",
"timestamp": "0x5cef4ec9",
"fullShardId": "0x1",
"chainId": "0x0",
"shardId": "0x0",
"blockId": "0x2e86e836527ffe5a2244638955697c0af59c6140057cc08d891e7ea04000844a00000001",
"blockHeight": "0x1b64a",
"transactionIndex": "0x0",
"from": "0x04e823bfd0ee5a05f072c346282e252e15cca98d",
"to": "0xd0bb6e0ed6c2e083274af28baa62d0953e4cfb28",
"fromFullShardKey": "0x0000c32e",
"toFullShardKey": "0x0000f295",
"value": "0x8ac7230489e80000",
"gasPrice": "0x2540be400",
"gas": "0x5208",
"data": "0x",
"networkId": "0xff",
"transferTokenId": "0x8bb0",
"gasTokenId": "0x8bb0",
"transferTokenStr": "QKC",
"gasTokenStr": "QKC",
"r": "0xe838ced32695d6196feae149db2502adadb19ab24ff0e3ea974b967282757f59",
"s": "0x6c8d88598eece0d8be3eaf99185d26755c77f8372b129c920eb4a32183643e9b",
"v": "0x1b"
},
"id": 1
}
Gets transaction details with the transaction id returned from sendTransaction or sendRawTransaction.
Param Name | Type | Description |
---|---|---|
-- | DATA, 36 bytes | transaction id |
Return Value | Type | Description |
---|---|---|
blockHeight |
QUANTITY | integer of the block number this transaction was in |
blockId |
DATA, 36 bytes | hash of the block this transaction was in + full shard id |
data |
DATA | data sent along with the transaction |
from |
DATA, 20 bytes | sender's address, NOT including fromFullShardKey |
fromFullShardKey |
QUANTITY, 4 bytes | sender's full shard key |
toFullShardKey |
QUANTITY, 4 bytes | recipient's full shard key |
gas |
QUANTITY | gas provided by the sender |
gasPrice |
QUANTITY | gas provided by the sender in Wei |
gasTokenId |
QUANTITY | the id of the gas token |
transferTokenId |
QUANTITY | the id of the transfer token |
gasTokenStr |
STRING | the symbol of the gas token |
transferTokenStr |
STRING | the symbol of the transfer token |
hash |
DATA, 32 bytes | hash of the transaction |
id |
DATA, 36 bytes | the full transaction id with the fromFullShardKey appended |
networkId |
QUANTITY | integer of the id of the network (e.g. devnet, mainnet) |
chainId |
QUANTITY | integer of the id of the chain |
shardId |
QUANTITY | integer of the id of the shard |
nonce |
QUANTITY | number of transactions made by the sender prior to this one |
timestamp |
QUANTITY | unix time of the block this transaction is in (bigint) |
to |
DATA, 20 bytes | recipient's address, NOT including toFullShardKey |
transactionIndex |
QUANTITY | integer of this transaction's index position in the block |
v |
QUANTITY | ECDSA recovery id |
r |
DATA, 32 bytes | ECDSA signature r |
s |
DATA, 32 bytes | ECDSA signature s |
value |
QUANTITY | value transferred in Wei |
getTransactionReceipt
curl -X POST --data '{
"jsonrpc": "2.0",
"method": "getTransactionReceipt",
"params": ["0x74bea8114c65bab71e24bf0c87499edfe17486de259954c2102c26aca597d5f90006c32e"],
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": {
"transactionId": "0x74bea8114c65bab71e24bf0c87499edfe17486de259954c2102c26aca597d5f90006c32e",
"transactionHash": "0x74bea8114c65bab71e24bf0c87499edfe17486de259954c2102c26aca597d5f9",
"transactionIndex": "0x0",
"blockId": "0xe3da26573a8fe7e38c373df7e62aa5cd4da2ba628cf509c5bc9f8b877c4a428f00060001",
"blockHash": "0xe3da26573a8fe7e38c373df7e62aa5cd4da2ba628cf509c5bc9f8b877c4a428f",
"blockHeight": "0x281d6",
"blockNumber": "0x281d6",
"cumulativeGasUsed": "0x7530",
"gasUsed": "0x7530",
"status": "0x1",
"contractAddress": null,
"logs": []
},
"id": 1
}
Gets the receipt of a transaction.
Param Name | Type | Description |
---|---|---|
-- | DATA, 36 bytes | transaction id |
Return Value | Type | Description |
---|---|---|
transactionId |
DATA, 36 bytes | transaction id, same as what you passed in the request |
transactionHash |
DATA, 32 bytes | transaction id minus the full shard id = the hash of the transaction |
transactionIndex |
QUANTITY | integer of this transaction's index position in the block |
blockId |
DATA, 36 bytes | hash of the block this transaction was in + full shard id |
blockHash |
DATA, 32 bytes | hash of the block |
blockHeight |
QUANTITY | integer of the block number this transaction was in |
blockNumber |
QUANTITY | integer of the block number this transaction was in |
cumulativeGasUsed |
QUANTITY | total amount of gas used when this transaction was executed in the block |
gasUsed |
QUANTITY | amount of gas used by this transaction alone |
status |
QUANTITY | either 1 (success) or 0 (failure) |
contractAddress |
DATA, 24 bytes | address of the contract created, if there was a contract created |
logs |
JSONR array | logs of contract invocation, with same structure as in Ethereum |
getLogs
curl -X POST --data '{
"jsonrpc": "2.0",
"method": "getLogs",
"params": [{
"topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]
}, "0x12345678"],
"id": 1
}'
# Result
{
"id":1,
"jsonrpc":"2.0",
"result": [{
"logIndex": "0x1", // 1
"blockNumber":"0x1b4", // 436
"blockHeight":"0x1b4", // 436
"blockHash": "0x8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d",
"transactionHash": "0xdf829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf",
"transactionIndex": "0x0", // 0
"address": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d",
"recipient": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d",
"data":"0x0000000000000000000000000000000000000000000000000000000000000000",
"topics": ["0x59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a5"]
},{
...
}]
}
Gets the logs with given filter.
Param Name | Type | Description |
---|---|---|
-- | JSON object | topic filter, same as eth_getLogs |
-- | QUANTITY | full shard key |
The response is the same as eth_getfilterchanges
call
curl -X POST --data '{
"jsonrpc": "2.0",
"method": "call",
"params": [
{
"from": "0x04E823bfD0EE5a05f072C346282e252e15CCa98D0007c32e",
"to": "0xA21faADC19aEd9F34Cb7DAf75Ec451C538b75ca10007C53F",
"gasPrice": "0x0",
"gas": "0xf4240",
"data": "0x70a0823100000000000000000000000004e823bfd0ee5a05f072c346282e252e15cca98d",
"value": "0x0",
"gasTokenId": "0x8bb0",
"transferTokenId": "0x8bb0"
},
"latest"
],
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": "0x00000000000000000000000000000000000000000000c0b332e7b55d5cc00000",
"id": 1
}
Executes the byte code on the blockchain without creating a transaction.
Param Name | Type | Description |
---|---|---|
Roughly the same as sendTransaction, except that full shard key is directly included in address (thus 24 bytes) |
Return Value | Type | Description |
---|---|---|
-- | DATA | the return value of the executed contract |
estimateGas
curl -X POST --data '{
"jsonrpc": "2.0",
"method": "estimateGas",
"params": [
{
"data": "0x",
"from": "0x04E823bfD0EE5a05f072C346282e252e15CCa98D0006C32E",
"gasTokenId": "0x8bb0",
"to": "0x7CBb25b228D9719d7061c5c91E396F3f1a405A9c0001C53F",
"transferTokenId": "0x8bb0"
}
],
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": "0x7530",
"id": 1
}
Estimates the gas usage of a transaction.
Param Name | Type | Description |
---|---|---|
Same as Call, while gas field is not needed |
Return Value | Type | Description |
---|---|---|
-- | QUANTITY | the amount of gas used |
gasPrice
curl -X POST --data '{
"jsonrpc": "2.0",
"method": "gasPrice",
"params": ["0x0006C32E", "0x8bb0"],
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": "0x2540be400", //10000000000
"id": 1
}
Returns the current price per gas in wei on the specified chain/shard for the specified token (default to QKC if argument not provided).
Param Name | Type | Description |
---|---|---|
-- | QUANTITY, 4 bytes | full shard key, see Address section for more details |
-- | QUANTITY | optional token ID, will default to QKC if not provided |
Return Value | Type | Description |
---|---|---|
-- | QUANTITY | integer of the current gas price in wei |
getRootBlockById
curl -X POST --data '{
"jsonrpc": "2.0",
"params": ["0x2a629116ab42c5856eaa73bc9a7ba4d81aeedf3810a64536f50b61d4276401e3"],
"method": "getRootBlockById",
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": {
"id": "0x2a629116ab42c5856eaa73bc9a7ba4d81aeedf3810a64536f50b61d4276401e3",
"hash": "0x2a629116ab42c5856eaa73bc9a7ba4d81aeedf3810a64536f50b61d4276401e3",
"height": "0x4b9",
"idPrevBlock": "0x43e1f7803c27d4733a1f859b6322c0ec01b4456250e3673274aefe19ef053971",
"hashPrevBlock": "0x43e1f7803c27d4733a1f859b6322c0ec01b4456250e3673274aefe19ef053971",
"nonce": "0x0",
"hashMerkleRoot": "0x9f8cffcea426dd7589dcc256e8f4d6916c18f29ca2f50498363fdac22495c845",
"miner": "0x199bcc2ebf71a851e388bd926595376a49bdaa329c6485f3",
"coinbase": [
{
"tokenId": "0x8bb0",
"tokenStr": "QKC",
"balance": "0x8fc3e4ad1a0ff0000"
}
],
"difficulty": "0x164ffb",
"timestamp": "0x5b2a8d9e",
"size": "0x1ddac",
"minorBlockHeaders": [
{
"id": "0x80b8261dec92b2c2a33eb31e0c7c55387ef7583161bee84042696aadec9c0e7900050001",
"height": "0x7b2f1",
"hash": "0x80b8261dec92b2c2a33eb31e0c7c55387ef7583161bee84042696aadec9c0e79",
"fullShardId": "0x50001",
"chainId": "0x5",
"shardId": "0x0",
"hashPrevMinorBlock": "0x4621beafb7f56b2bfe6ef51783418757e3dca3716f5663af11bacdf19e4f4fbe",
"idPrevMinorBlock": "0x4621beafb7f56b2bfe6ef51783418757e3dca3716f5663af11bacdf19e4f4fbe00050001",
"hashPrevRootBlock": "0xc811deee2a7345f286132f221672c61bbdfae45aa0d7c069866037b9494f3609",
"nonce": "0xfa1cf37c07150503",
"difficulty": "0x9e9ff7458",
"miner": "0xd786c575068c3d599739a7c11356361aa36389ae00050001",
"coinbase": [
{
"tokenId": "0x8bb0",
"tokenStr": "QKC",
"balance": "0x2d1a51c7e0050000"
}
],
"timestamp": "0x5d1548ef"
},
…
]
}
}
Get root block details by root block id.
Param Name | Type | Description |
---|---|---|
-- | DATA, 32 bytes | root block id |
Return Value | Type | Description |
---|---|---|
id |
DATA, 32 bytes | root block id (also the hash); they are the same since we don't have shard ids at the root block level |
hash |
DATA, 32 bytes | hash of the root block (also the id) |
height |
QUANTITY | integer of the root block number |
idPrevBlock |
DATA, 32 bytes | id of the previous block (same as hash) |
hashPrevBlock |
DATA, 32 bytes | hash of the previous block (same as id) |
nonce |
DATA, 8 bytes | hash of the generated proof-of-work |
hashMerkleRoot |
DATA | hash of the merkle root for this root block |
miner |
DATA, 20 bytes | address of the beneficiary to whom the mining rewards were given |
coinbase |
JSON object | coinbase tokens rewarded to the miner |
difficulty |
QUANTITY | integer of the difficulty for this block |
timestamp |
QUANTITY | unix time of the root block |
size |
QUANTITY | integer of the size of this block in bytes |
minorBlockHeaders |
JSON array | minor block headers included in this root block |
getRootBlockByHeight
Get root block details by height.
Param Name | Type | Description |
---|---|---|
-- | QUANTITY | integer of the root block number. if not provided, will default to latest height |
Return Value | Type | Description |
---|---|---|
Same as in getRootBlockById |
getMinorBlockById
curl -X POST --data '{
"jsonrpc": "2.0",
"params": ["0x80b8261dec92b2c2a33eb31e0c7c55387ef7583161bee84042696aadec9c0e7900050001", false],
"method": "getMinorBlockById",
"id": 1
}'
# Result
{
"jsonrpc": "2.0",
"result": {
"id": "0x80b8261dec92b2c2a33eb31e0c7c55387ef7583161bee84042696aadec9c0e7900050001",
"height": "0x7b2f1",
"hash": "0x80b8261dec92b2c2a33eb31e0c7c55387ef7583161bee84042696aadec9c0e79",
"fullShardId": "0x50001",
"chainId": "0x5",
"shardId": "0x0",
"hashPrevMinorBlock": "0x4621beafb7f56b2bfe6ef51783418757e3dca3716f5663af11bacdf19e4f4fbe",
"idPrevMinorBlock": "0x4621beafb7f56b2bfe6ef51783418757e3dca3716f5663af11bacdf19e4f4fbe00050001",
"hashPrevRootBlock": "0xc811deee2a7345f286132f221672c61bbdfae45aa0d7c069866037b9494f3609",
"nonce": "0xfa1cf37c07150503",
"hashMerkleRoot": "0xdaa77426c30c02a43d9fba4e841a6556c524d47030762eb14dc4af897e605d9b",
"hashEvmStateRoot": "0xbad1c1f7b40d35b6e2e22a2821baafe79c754a8c075bb2d4907c8cd108023716",
"miner": "0xd786c575068c3d599739a7c11356361aa36389ae00050001",
"coinbase": [
{
"tokenId": "0x8bb0",
"tokenStr": "QKC",
"balance": "0x2d1a51c7e0050000"
}
],
"difficulty": "0x9e9ff7458",
"extraData": "0x",
"gasLimit": "0xb71b00",
"gasUsed": "0x0",
"timestamp": "0x5d1548ef",
"size": "0x314",
"transactions": []
},
"id": 1
}
Get shard block details by block ID.
Param Name | Type | Description |
---|---|---|
-- | DATA, 36 bytes | minor block id |
-- | BOOL | true to return transactions with the minor block |
Return Value | Type | Description |
---|---|---|
id |
DATA, 36 bytes | minor block id (includes full shard id as last 4 bytes) |
height |
QUANTITY | integer of the minor block number |
hash |
DATA, 32 bytes | hash of the minor block |
fullShardId |
QUANTITY | integer of the full shard ID; see Address section for more details |
chainId |
QUANTITY | integer ID of the chain |
shardId |
QUANTITY | integer ID of the shard |
hashPrevMinorBlock |
DATA, 32 bytes | hash of the previous minor block |
idPrevMinorBlock |
DATA, 36 bytes | id of the previous minor block (includes full shard id) |
hashPrevRootBlock |
DATA, 32 bytes | id/hash of the root block it points to |
nonce |
DATA, 8 bytes | hash of the generated proof-of-work |
hashMerkleRoot |
DATA, 32 bytes | the merkle root for this minor block |
hashEvmStateRoot |
DATA, 32 bytes | the root of the evm state trie for this minor block |
miner |
DATA, 20 bytes | address of the beneficiary to whom the mining rewards were given |
coinbase |
JSON object | coinbase tokens rewarded to the miner |
difficulty |
QUANTITY | integer of the difficulty for this block |
extraData |
DATA | the "extra data" field of this block |
gasLimit |
QUANTITY | the maximum gas allowed in this block |
gasUsed |
QUANTITY | the total gas used by all transactions in this block |
timestamp |
QUANTITY | unix time of the root block |
size |
QUANTITY | integer of the size of this block in bytes |
transactions |
JSON array | list of the transactions in this block |
getMinorBlockByHeight
curl -X POST --data '{
"jsonrpc": "2.0",
"params": [
"0x50001",
"0x7b2f1",
false
],
"method": "getMinorBlockByHeight",
"id": 1
}'
Gets minor (shard) block details by shard and height.
Param Name | Type | Description |
---|---|---|
-- | QUANTITY | integer of the full shard ID; see Address section for more details |
-- | QUANTITY | integer of the minor block number. if not provided, will default to latest height |
-- | BOOL | true to return transactions with minor block |
Return Value | Type | Description |
---|---|---|
Same as getMinorBlockById |
getRootHashConfirmingMinorBlockById
curl -X POST --data '{
"jsonrpc": "2.0",
"params": [
"0xab4b1d46c28d00bdc2cbe484440ed2f35715291a3bbca2b9bea09e1ff739012600000002"
],
"method": "getRootHashConfirmingMinorBlockById",
"id": 1
}'
Gets the root block that has included the minor block from the query.
Param Name | Type | Description |
---|---|---|
-- | DATA, 36 bytes | minor block id (hash+full_shard_id) |
Return Value | Type | Description |
---|---|---|
-- | DATA, 32 bytes | id/hash of the root block that has included the minor block from the query |
getTransactionConfirmedByNumberRootBlocks
curl -X POST --data '{
"jsonrpc": "2.0",
"params": [
"0x1ff935396d9645aba36209b68f16aad3105f723a03c5c6468734c1be22a24c4700000000"
],
"method": "getTransactionConfirmedByNumberRootBlocks",
"id": 1
}'
Gets the root block that has included the minor block from the query.
Param Name | Type | Description |
---|---|---|
-- | DATA, 36 bytes | transaction id |
Return Value | Type | Description |
---|---|---|
-- | QUANTITY | number of rootblocks that has confirmed the transaction; or None if the transaction has not been included by a minor block |