Transactions

Transaction Finality

Block finality refers to the concept that a proposed block is finalized by the blockchain and can not be reverted or the cost of reversion is prohibitively high. Block finality is usually measured by how long it takes for the newly proposed blocks to be finalized. For example, in Ethereum, it takes more than 6 blocks or 1 minute to have reasonable confidence that the block is finalized and can not be reverted.

Thanks to the nature of POSI Chain FBFT consensus, blocks can be finalized as long as the 2/3 majority quorum is reached on the block. On the POSI Chain mainnet, it now takes 2 seconds to finalize a newly proposed block and the transactions inside.

Transaction Fees

POSI Chain follows the same transaction fee model as Ethereum where users pay a certain amount of tokens to get their transactions processed and included in the blockchain. Since POSI Chain is fully EVM-compatible, users can translate directly the fee model from Ethereum and apply to POSI Chain. For example, a normal token transfer transaction cost 21000 gas. The gas price can be as low as 0.0000001 POSI (or 100 Gwei as in Ether) since POSI Chain have high TPS and the network is highly efficient and rarely clogged. This means a normal transfer cost only about 0.00021 POSI. In General, transactions POSI Chain in network cost around $0.0000315 gas fee.

The reason for POSI Chain to be able to afford such low fee is twofold. First, POSI Chain is Proof-of-Stake chain where the cost of running a node is much cheaper than PoW chains as no wasteful computation is needed. Second, POSI Chain is a highly scalable blockchain which currently provide thousands of transactions per seconds as throughput. This means users don't need to bid with high fee to get their transaction processed in time. We expect the low fee situation will stay as long as POSI Chain network is not fully utilized and even if that happens, we can solve the problem by extending the network with more shards to provide more transaction processing power.

Cross-Shard Smart Contract Transaction

We will adopt the asynchronous cross-shard communication model just like we did for cross-shard POSI token transfer. Meaning any smart contract which needs to call another smart contract from another shard will have the sender contract transaction finalized first at initiating shard, then a receipt will be created including the call data, and finally the receipt will be sent and processed at the destination shard.

A new Opcode “CALL2” will be added to the virtual machine which is used for a cross-shard smart contract call.

CALL2’s input is similar to CALL but with an another shardID parameter:

(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int, shardID uint32)

Unlike CALL which actually executes the contract code within the same shard, CALL2 won’t run any code but only lead to the creation of a receipt after the transaction is successfully confirmed in this block. The receipt structure can be like this:

// CXReceipt represents a receipt for cross-shard transaction
type CXReceipt struct {
  TxHash    common.Hash // hash of the cross shard transaction in source shard
  Sender    common.Address
  From      common.Address
  To        common.Address
  ShardID   uint32
  ToShardID uint32
  Input     []byte
  Amount    *big.Int
  Gas       uint64
}

Specifically:

  • TxHash: the transaction hash of the original transaction sent from the real user

  • Sender: the address of the transaction sender

  • From: the address of the caller smart contract which initiated the cross-shard call

  • To: the address of the callee smart contract in another shard

  • ShardID: the shardID of the caller smart contract

  • ToShardID: the shardID of the caller smart contract

  • Input: the input data for the smart contract call, exactly like the payload of a normal intra-shard transaction that calls a smart contract

  • Amount: is the among of ONE that is sent along with the call to the callee smart contract

  • Gas: the gas that’s going to be paid to the destination shard.

Once the corresponding block of the receipt is finalized, a proof data for the receipt will also be generated. This is exactly the same as cross-shard POSI token transfer:

// CXReceiptsProof carrys the cross shard receipts and merkle proof
type CXReceiptsProof struct {
  Receipts     CXReceipts
  MerkleProof  *CXMerkleProof
  Header       *block.Header
  CommitSig    []byte
  CommitBitmap []byte
}

Once the receipt and proof are obtained, they will be sent from source shard to destination shard (CXReceipt.ToShardID) for processing.

The destination shard process the cross-shard smart contract receipt by:

  1. Verify the receipt is valid using the proof data

  2. Use the CXReceipt.To as the callee smart contract address and CXReceipt.Input data as the contract call data for contract execution. CXReceipt.Amount and CXReceipt.Gas are also used the same way as normal contract calls.

  3. If this contract call produces additional cross-shard contract calls. Additional receipts will be generated and the same cross-shard call process will happen.

Design Questions:

  1. What if the callee contract doesn’t exist in the destination shard?

    1. We could simply abort the cross-shard call but credit the gas to the destination shard. This way, we don’t need another cross-shard receipt to go back to the source shard to credit the gas.

    2. Or we could create a brand new contract. This requires the receipts include the contract bytecode which can be user specified or the same as the caller contract’s code.

  2. What if the gas sent in the receipt is not enough to pay for the transaction?

    1. Simply abort the contract call as a normal transaction “Out of Gas” situation.

  3. In any failure cases of the cross-shard contract call. The sent token in CXReceipt.Amount should be credited to?

    1. The sender address in the destination shard. This avoids having to send another cross-shard receipt to credit the token back to the sender shard.

Last updated