# Introduction

Here is the document site for smartBCH.

If you just want to know general information about smartBCH, the [white paper](/smartbch/smartbch_whitepaper-en) and [FAQ](/smartbch/faq) would be enough.

From a DApp developer's view, smartBCH is just yet another EVM-compatible block chain, similar to BSC, heco and Tron. But since the underlying architecture of smartBCH has MANY differences from Ethereum, there are some issues that developers must be aware of. So we provide [developers guides](/smartbch/developers-guide/intro) here.

If you are a researcher or a low-level library hacker, you may be interested in the several moeing\*\*\* libraries provided by smartBCH. They are the core innovations and infrastructure for high TPS. If you want to learn their details or use them in other projects, here is [in-depth introduction](/smartbch/in-depth-design-documents/intro).

You can join smartBCH with a full-node client by following [this guide](/smartbch/mainnet).

The decentralized bridge connecting BCH and smartBCH is named as [SHA-Gate](broken://pages/-MgfdA0E2SCWjtBduuvU). The developers are now busy in studying its feasibility and safety, with coding and implementation followed soon. We invite the BCH community to help us review and refine SHA-Gate, to speed up its development.

The SEPs are **s**martBCH **e**volution **p**roposals, in which the community discusses future direction of smartBCH.

There is also some operation guides for validators and gateway keepers of smartBCH.

If you find some issues in these documents, please report them at <https://github.com/smartbch/docs/issues>.


# Whitepaper

## Abstract

While Bitcoin Cash aims to provide a decentralized, high-throughput, low-cost, and easy-to-use infrastructure for cryptocurrency; any changes to the mainnet require a high level of consensus, which hinders the trial-and-error process.

So, we decided to develop Smart Bitcoin Cash - a sidechain for Bitcoin Cash with an aim to explore new ideas and unlock possibilities. It will be compatible with Ethereum's EVM and Web3 API, for they are the de facto standards for blockchain DApps nowadays.

Ethereum is solving the issues related to low-throughput and high-cost by switching to ETH2.0, which, as we all know, still requires years of development to finish. Smart Bitcoin Cash attempts to tackle these issues differently, by optimizing the implementation of EVM and Web3 at a low-level in order to fully leverage the potential of hardware, especially its inherent parallelism. We believe that Smart Bitcoin Cash will provide the same benefits of ETH2.0 in a much shorter time.

## Motivation

Different people want different new features from Bitcoin Cash.

Bitcoin Cash's block interval remains 10 minutes, which is too long by comparison, as there are other chains offering intervals of seconds. Although Bitcoin Cash supports secure zero-confirmation transactions, complex scenarios besides payments need short confirmation times for better user experience, such as DeFi.

Bitcoin Cash has a limited script system which is not Turing-complete, making it more difficult to use than Ethereum's EVM. Also, it is less capable than EVM and Solidity, as they offer the best ecosystem and encompass the most programmers among all the smart contract platforms. It's a pity they cannot be utilized in Bitcoin Cash's ecosystem.

Currently, Bitcoin Cash's capability has been proven to [reach 14MB](https://news.bitcoin.com/new-bitcoin-cash-stress-test-sees-700000-transactions-in-one-day/). Although at this moment its block size is only 0.8 MB on average, it is growing fast: more than three times since the beginning of 2021. If it keeps growing at such a rate, 14MB would not be enough in the near future. Since issues surrounding block size larger than 14MB remain unknown and have not been field-tested, it would be best to begin getting prepared for further scaling of Bitcoin Cash's throughput.

What can Smart Bitcoin Cash contribute to the Bitcoin Cash ecosystem? Well, it builds a new playground for testing new features: It has a short confirmation time, supports EVM and Web3 with novel optimizations to provide higher throughput, and also provides new channels for one to invite more users to join Bitcoin Cash's ecosystem.

As Smart Bitcoin Cash grows more mature, the developed libraries and the learned lessons will help improve Bitcoin Cash's mainnet, too.

## Background

It has been 8 years since Vitalik Buterin proposed Ethereum in 2013. Smart contracts were born, bred, and have been blooming ever since. Ethereum is now the most successful smart contract platform, and we may examine its ecosystem as well as make observations from it:

**The single chain's user experience is hard to approach through sharding or layer-2 solutions**. Zero latency and atomic interoperation between smart contracts is only possible within the same chain. The cross-shard or layer-2-to-layer-1 interoperation must undergo an interchain communication process, which prompts latencies similar to depositing and withdrawing at centralized exchanges. Some popular mechanisms, such as [flash loan](https://wwz.unibas.ch/fileadmin/user_upload/wwz/00_Professuren/Schaer_DLTFintech/Lehre/MA_Florian_Gronde_Flashloans-ohne_Appendix.pdf) and [flash swap](https://uniswap.org/docs/v2/core-concepts/flash-swaps/), would not work cross-chain.

**Low-throughput deters ordinary users from interacting directly with DApps**. The gas upper bound is fixed for each block, and miners pack the transactions with high gas fees first. Meanwhile, transactions with low gas fees must wait a long time to be packed into a block or never get packed at all. Naturally, only high-value transactions are worth a high gas fee. So, ordinary users who cannot afford high gas fees can only deposit their funds into centralized organizations, then delegate them to operate their funds. In the DeFi world, only a small number of accounts are sending transactions. These accounts have a lot of funds, either because they own a lot, or because they gather a lot from ordinary users. Ironically, today's decentralized finance is not so decentralized.

**Storage costs more resources than computation when executing smart contracts**. In the history of Ethereum, the storage's gas cost has been increased by two EIPs: [EIP-1884](https://eips.ethereum.org/EIPS/eip-1884) and [EIP-2200](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2200.md). But that is not enough, as [Research](https://arxiv.org/pdf/1909.07220.pdf) shows that Ethereum still underestimates certain storage operations, making it susceptible to DoS attacks. So, another EIP, [EIP-2929](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2929.md), is about to increase the gas of high storage operations again in the upcoming Berlin hard fork. At the same time, the 256-bit arithmetic of EVM is speeded up substantially by new libraries from [Martin Holst Swende](https://github.com/holiman/uint256) and [Paweł Bylica](https://github.com/chfast/intx).

**Off-chain QPS (queries per second) is as important as on-chain TPS (transactions per second)**. A DApp works by not only sending a transaction for execution but also querying the latest on-chain state and the chain's historical events. Though a transaction is executed only once, the corresponding events and state changes may be queried many times. So the total requirements for QPS are much higher than TPS. In Ethereum's ecosystem, the queries are made through Web3 API, the largest provider of which is Infura. Infura maintains an [optimized](https://blog.infura.io/faster-logs-and-events-e43e2fa13773/) Web3 implementation, which is better than standard full node clients, such as [go-ethereum](https://github.com/ethereum/go-ethereum), but is not open-sourced. Many developers choose to use Infura's low-cost service instead of running their own full nodes. Consequently, if Infura experiences [a severe service interruption](https://blog.infura.io/infura-mainnet-outage-post-mortem-2020-11-11/), many DApps and exchanges would fail to work.

**Users are quite tolerant of transaction latency and do not pay much attention to the exact order of transactions**. Usually, we use a wallet such as MetaMask to sign transactions, for which a proper gas price is chosen before broadcast. To save gas fees, we often choose a lower gas price and expect the transaction to be confirmed in minutes or even hours, instead of in the next block. In some cases, some other transactions may be packed before yours, resulting in losses such as larger slippage. But most users can live with that.

We also observed that, since 2013, the most important trend in computers is **adding more cores to CPUs**. Let's compare a MacBook in 2013 and in 2021, and predict how it will be like in 2029:

|                       | MacBook Pro in 2013 | MacBook Pro in 2021 | MacBook Pro in 2029 |
| --------------------- | ------------------- | ------------------- | ------------------- |
| # CPU cores           | 2                   | 8                   | 32                  |
| Highest CPU Frequency | 2.9GHz              | 3.1GHz              | 3.3GHz              |
| Lithography for CPU   | 22nm                | 5nm                 | 1nm                 |

Integrated circuit technology can hardly boost frequency further after 28nm; however, it does provide more transistor budget in the new generations. Designers may use these transistors to implement more and more CPU cores. In the last decade, surrounding all the novel programming languages hype, is the easy leveraging of the potential of more CPU cores: [channels and goroutines](https://medium.com/hootsuite-engineering/golang-routines-and-channels-dff7336eb457) of Go, [isolates](https://medium.com/dartlang/dart-asynchronous-programming-isolates-and-event-loops-bffc3e296a6a) of Dart, and [fearless concurrency](https://doc.rust-lang.org/book/ch16-00-concurrency.html) of Rust.

The above observations shall guide the design and implementation of Smart Bitcoin Cash.

## Core Components of Smart Bitcoin Cash

Smart Bitcoin Cash's innovation lies in libraries. Instead of inventing fancy consensus and cryptographic algorithms, we decided to adopt another methodology: to develop low-level libraries with an aim to fully uncover the hardware's potential, especially its inherent parallelism. Ordinary users and developers are provided with a compatibility layer supporting EVM and Web3, so the optimized low-level "close to the metal" libraries themselves remain concealed by this layer of abstraction. During the implementation, we used the codename "Moeing", which is added to the libraries' names as prefix.

With these powerful components, Smart Bitcoin Cash aims to enlarge the gas consumption every 15 seconds to one billion gas in the medium term. In the long run, overall throughput will be boosted further by adopting sharding and rollups.

### MoeingEVM

MoeingEVM is a parallelized execution engine that currently manages multiple EVM contexts and executes multiple transactions. Based on an optimized EVM implementation from [evmone](https://github.com/ethereum/evmone), it can be observed that there are several novel techniques adopted to maximize transaction parallelism.

As multi-core CPUs become more and more popular, scalability would be hindered in the context of Ethereum's single-thread execution semantics, because under its constraint speeding up is very hard. But if we switch to multi-thread execution semantics, a better overall result would be achieved as multi-core CPUs can be utilized more easily and in a more straightforward manner.

So MoeingEVM is developed following the multi-thread execution semantics.

To fully utilize the inherent parallelism in modern hardware, we attempt to leverage two kinds of parallelism:

1. The parallelism between consensus engine and transaction execution engine.
2. The parallelism among different transactions.

To make consensus engine and transaction execution engine work concurrently, MoeingEVM uses such a scheme: when a block is committed, the transactions in it would not be executed immediately. Instead, these transactions would be saved as a part of the world state. After they are saved, the Merkle root of the world state would be calculated and the next block will be proposed and determined; meanwhile, the saved transactions will be examined and executed.

To make EVMs run in parallel, we allow transactions from several blocks to be mixed and reordered. In each round, a bundle of independent transactions is picked and executed in parallel to achieve a higher degree of concurrency. After several rounds, all or part of the saved transactions get executed, whereas the remaining unexecuted transactions are saved back to the world state for later execution. Since transactions are always enforced into bundles and each bundle is executed in parallel, this scheme is named "**enforced-bundle parallelism** (EBP)".

[EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) makes a transaction explicitly containing a list of addresses and storage keys that it plans to access. This list helps analyze the interdependence of transactions. In the future, MoeingEVM will utilize it to further boost the parallelism of transaction execution.

Besides more parallelism, MoeingEVM also reorders transactions in a pseudo random way to mitigate the problem of front-running, which makes it much harder for a validator to enforce its preferred transaction order.

### MoeingADS

Why are storage operations so expensive? Well, Ethereum’s storage engine MPT is absolutely the root cause.

Is it okay to skip MPT? Yes, many blockchains (including Bitcoin Cash) work well without it. However, as an authenticated data structure capable of proving what states do or do not exist in the world state, it remains very important for trustlessness and is the cornerstone for light clients and chain-crossing.

So we move forward to develop MoeingADS — another authenticated data structure capable of replacing MPT.

Ethereum’s storage engine has a two-layer architecture. The first is LevelDB and the second is MPT. On the other hand, blockchains such as Bitcoin Cash adopt a single-layer architecture for storage — using LevelDB to store UTXOs directly. MPT works on top of LevelDB to be an authenticated data structure, at the cost of a lower read & write throughput. Every time the EVM reads or writes the world state, MPT must perform several LevelDB operations, prompting multiple operations on the SSD, resulting in the slowness of MPT.

MoeingADS uses a single-layer architecture, accessing the file system directly without having to use any other databases. It is a KV database that can provide existence and non-existence proof. With MoeingADS, reading a KV pair requires one read to disk, overwriting a KV pair requires one read and one write, inserting requires two reads and two writes, and deleting requires two reads and one write. What’s more, the writes are appending, which is very SSD-friendly.

Experiments show that MoeingADS is even faster than LevelDB. The cost is the larger consumption of DRAM: each key-value pair demands about 16 bytes.

### MoeingDB

Besides supporting MPT, LevelDB is also commonly used to store historical data such as blocks, transaction receipts, and logs. However, it is not optimized for blockchain workloads, which carry the following characteristics:

1. Read volume is much larger than write volume.
2. No need to support Read-Modify-Write atomic transactions.
3. Simple read/write locks are better than [MVCC](https://en.wikipedia.org/wiki/Multiversion_concurrency_control), as modifications are large batched writes for blocks.
4. Poor spatial locality for efficient caching, which results from most keys being Hash IDs.
5. Susceptible to DDoS attack, unless cold data’s read latency has a reasonable upper bound.

MoeingDB is an application-specific database that stores blockchain history, and we developed it with the above characteristics in mind to suit blockchain's workload best. Based on its features, an open-source high QPS Web3 API can be built, benefiting both Smart Bitcoin Cash and Ethereum. We hope that it will facilitate the Web3 API provider market to be more decentralized.

### MoeingKV

MoeingKV is a KV storage much faster than LevelDB in reading and writing, at the cost of removing iteration support.

To support iterators, LevelDB involves a lot of trade-offs and optimizations. But in most cases, blockchain storage engines can work without iterators, with examples like Ethereum’s MPT and Bitcoin Cash’s UTXO storage.

In underlying data structure design and code implementation, MoeingKV produces trade-offs and optimizations to speed up normal read and write operations. So, it can replace LevelDB as a better “first layer” for MPT.

While MPT cannot be replaced by MoeingADS due to compatibility, one can use MoeingKV to support MPT. MPT backed by MoeingKV might not be as fast as MoeingADS, but it is much faster than one backed by LevelDB.

Though MoeingKV is not used in Smart Bitcoin Cash, its key ideas come from MoeingADS and MoeingDB. We particularly hope other projects may benefit from MoeingKV.

### MoeingAOT

MoeingAOT is an ahead-of-time compiler for EVM.

EVM, which is adopted more commonly than other VMs like WebAssembly, is a de facto standard for smart contracts.

However, EVM lacks certain important speedup methods, such as ahead-of-time (AOT) compilers and just-in-time (JIT) compilers. In the software industry, almost every important VM has its AOT and/or JIT compilers, for example, JVM, ART VM, Javascript V8, DartVM, WebAssembly, LuaJIT, and GraalVM. We believe that it is about time that EVM has its compiler. And implementing an AOT compiler for it would be reasonable, since, unlike Javascript and Lua, it has static semantics.

MoeingAOT can compile EVM bytecode into native code, which would consequently be saved as a dynamically linked library. When the EVM interpreter starts running a smart contract and finds its corresponding compiled library file, the library will be loaded and run, and bytecode interpretation wouldn’t be necessary.

For the frequently used contracts, such as USDT and UniSwap, ahead-of-time compilation is valuable because native code is much faster than interpretation, which reduces the execution time drastically.

### MoeingRollup

Rollup is an offload methodology to scale up a chain's throughput. Different projects, such as [optimistic rollup](https://optimism.io/) and [arbitrum rollup](https://offchainlabs.com/), have different implementations. Generally speaking, rollup means rolling up a whole set of states into one commitment, meaning one state root. Usually, one rollup extension resides inside a smart contract and a sequencer maintains its states, packs users' transactions into blocks, and submits the respective state roots into the smart contract. The transition between the state roots of two adjacent blocks can be validated with some proof data.

An honest sequencer must reliably maintain the states and neutrally packs users' transactions, which means without any censorship. It must also provide the states and blocks to anyone in need; otherwise, users may evict it and find a new replacement using some staking mechanism predefined in the smart contract.

Furthermore, the submitted state roots sequence must be linked with valid transitions between adjacent roots. If an invalid one is located, the sequencer may be challenged to provide the proof data. And when the sequencer fails to do so, he will be slashed and evicted.

The detailed running rules are defined in smart contracts and may vary in different rollup extensions. Anyway, their common purpose is to prove valid state transition with proof data. Unfortunately, the proving task is quite heavy and hard to implement in EVM.

MoeingRollup implements this proving task natively. Using a primitive for smart contracts, all the rollup extensions can perform the proving tasks easily and efficiently. Proof data are required to encompass these three parts:

1. A block of transactions
2. The transactions' input KV pairs and their existence proof against starting state root
3. The transactions' output KV pairs and miscellaneous data for calculating the ending state root

At the same time, MoeingRollup also eases the sequencer's job by providing utilities, including proof data generation.

### MoeingLink

Smart Bitcoin Cash will start as a single-shard chain. But in the long run, it is possible to include more shards and transform them into a multi-shard chain.

MoeingLink is a protocol enabling different shards to interact directly without executing any transactions on Bitcoin Cash's mainnet.

Currently, all major sharding solutions require an intermediate chain. In ETH2.0, it's the beacon chain, and in Polkadot, it's the relay chain. As more and more shards are created, the inter-shard transactions will produce a huge pressure on the crowded layer-1.

To avoid that, MoeingLink allows shards to prove self-state to others, utilizing MoeingADS's state roots committed on layer-1. Once they have acknowledged each other’s state, they can interact directly without the help of layer-1.

## The Consensus Algorithm

Smart Bitcoin Cash adopts [tendermint](https://github.com/tendermint/tendermint) as its consensus engine. The quorum of validators are elected by both hash power and BCH owners, and they take on duties in epochs.

An epoch contains 2,016 blocks (takes about two weeks). During an epoch, BCH owners prove their ownerships of time-locked UTXOs and use the values of these UTXO to vote for a validator; whereas mining pools use coinbase transactions to vote. This is a hybrid consensus model: proof of hash power and stakes. The voting process is performed on Bitcoin Cash's mainnet and totally permissionless because a new validator only needs endorsements from miners and/or holders.

An epoch's end time is the largest timestamp of its blocks, and its duration time is the difference between the end times of adjacent epochs. The quorum elected during an epoch will stay in a stand-by state for about 5% of the epoch's duration time. Then it takes its turn to be on duty, until the next quorum leaves its stand-by state, which is necessary because any Bitcoin Cash reorganization may alter the blocks in an epoch.

Each validator must pledge some BCH as collateral, which would be slashed should it misbehaves during its duty.

At the first phase after Smart Bitcoin Cash's launch, only hash power is used for electing validators. Locking BCH at mainnet for staking will be implemented later and take effect in a future hard fork.

## Token and Gas

Smart Bitcoin Cash will not introduce new tokens. Its native token is BCH, and its gas fees are paid in BCH.

At the end of a quorum‘s tenure, half of the collected gas fees will be rewarded to the validators and the other half will be burned. In this sense, BCH will become a deflationary currency. A validator must pledge enough collateral to get its gas fee reward, and the reward must undergo a lock period before it can be spent.

The [buyback-and-burn](https://medium.com/invao/buyback-and-burn-how-it-works-and-why-its-effective-cb2c7d9b9297) mechanism is very common for exchange tokens (BNB, HT, FTT, OKB, etc) and DeFi governance tokens. And Filecoin has a similar mechanism to [burn part of the gas fees](https://docs.filecoin.io/about-filecoin/how-filecoin-works/#gas-fees), which will be followed by Ethereum in [EIP-1559](https://medium.com/@TrustlessState/eip-1559-the-final-puzzle-piece-to-ethereums-monetary-policy-58802ab28a27). This mechanism has proven effective, so we decided to use it.

BCH can be transferred bidirectionally between Bitcoin Cash's mainnet and Smart Bitcoin Cash, which means we can lock certain coins on the mainnet, and unlock the same amount of coins on Smart Bitcoin Cash, and vice versa. To bootstrap Smart Bitcoin Cash, we are inviting the major players in Bitcoin Cash's ecosystem to run a federated two-way pegged gateway, which bridges the mainnet and Smart Bitcoin Cash to transfer BCH bidirectionally, just like how [RSK and Liquid](https://blog.rsk.co/noticia/the-cutting-edge-of-sidechains-liquid-and-rsk/) work. These players are not necessarily validators.

Nowadays the cryptocurrency communities have adapted to the "Same Symbol on Different Chains" scheme. For example, when mentioning USDT, it can refer a token on Bitcoin's Omni, Bitcoin Cash's SLP, Ethereum, Tron, etc. So we do not use another symbol to refer the BCH on Smart Bitcoin Cash, to avoid misunderstanding.

We are aware that Bitcoin Cash's scripting language is capable of implementing a non-custodial trustless gateway by using a lock script to trace the voting process carried out inside coinbase transactions. However, this scheme has not been field-proven. We will write up dedicated proposals to describe this scheme and it will be implemented in [CashScript](https://cashscript.org/) upon passing. Afterwards, Smart Bitcoin Cash will switch to this new scheme in a hard fork.

## Interoperation with other Layer-2 solutions on Bitcoin Cash

There are many layer-2 extensions on Bitcoin Cash to allow issuers to mint fungible and non-fungible tokens. Among them, the most successful and important one is [Simple Ledger Protocol (SLP)](https://simpleledger.cash/). In an SLP token's ecosystem, its issuer plays a central role, who can be helpful in the transfer of tokens across Smart Bitcoin Cash.

For example, if Alice wants to transfer 10 XYZ coins from SLP to Smart Bitcoin Cash, she can send the coins to XYZ's issuer using SLP, then XYZ's issuer will send her 10 coins on Smart Bitcoin Cash, and vice versa. To step up security for this process, Alice can use an atomic swap to ensure the transactions on each side both happen or neither happen.

## Roadmap

MoeingADS, MoeingEVM and MoeingDB are almost finished. Regardless, some throughput tests are necessary before Smart Bitcoin Cash can be officially launched.

MoeingAOT will be ready and take effect after a hard fork by the end of 2021. MoeingKV will also be developed in 2021 with the hope to meet potential demands from Bitcoin Cash's mainnet.

MoeingRollup and MoeingLink will be developed in 2022. By then, if the traffic of Smart Bitcoin Cash is congested, they will be deployed in a hard fork for further scaling.

## Conclusion

Smart Bitcoin Cash provides an EVM & Web3 compatible sidechain for Bitcoin Cash, staking its hash power while utilizing BCH as gas. What’s more, by incorporating hardware-friendly components, scalability is unlocked. We believe that it will provide the same benefits of ETH2.0 in a much shorter time, achieving a block gas limit of one billion.

The Smart Bitcoin Cash, to a large extent, can be viewed as a demo and an experiment of the novel and aggressive techniques we have been developing, which aim to optimize storage and execution engines for extreme throughput. Just like other open-source projects, there might be bugs and vulnerabilities in its design and implementation. So please be aware of the potential risks and make sure that possible losses are affordable when transferring your assets (including BCH) onto the Smart Bitcoin Cash.


# FAQ

> Smart Bitcoin Cash (smartBCH): a Bitcoin Cash Sidechain with EVM & Web3 Compatibility

FAQs are in progress and we are continuing to add as new questions arise. If you have a question that is not answered here, please ask in our [Telegram](https://t.me/smartbch_community), [Discord](https://discord.gg/7f6EzYJd), or [Twitter](https://twitter.com/SmartBCH).

See the FAQ sections below for topic-based questions and answers:

* smartBCH Basic
* Development Tools&#x20;
* Contact & Media Info

## SmartBCH Basic

### Q: What is smartBCH?

smartBCH is a sidechain for Bitcoin Cash and has an aim to explore new ideas and unlock novel possibilities. A sidechain is a blockchain designed for fast and inexpensive transactions with a special relationship with the main chain because of a two-way peg; in this case between Bitcoin Cash and smartBCH.

By developing optimized, high-throughput, and hardware-friendly libraries compatible with the de facto standards of smart contracts, DeFi applications can be easily migrated into Bitcoin Cash's ecosystem and run fluently at low cost.

### Q: What are smartBCH's key features?

Smart Bitcoin Cash's innovation lies in libraries to provide a compatibility layer supporting EVM and Web3 to users and developers. We are actively working on the following libraries:

* MoeingEVM: MoeingEVM is a parallelized execution engine that currently manages multiple EVM contexts and executes multiple transactions. It adopts several novel techniques to allow transactions from several blocks to be mixed and reordered, such that independent transactions can run in parallel to maximize throughput.
* MoeingADS: MoeingADS uses a single-layer architecture, accessing the file system directly without having to use any other databases. It is a KV database that can provide existence and non-existence proof. It can replace Ethereum's MPT as an authenticated data structure. With MoeingADS, reading a KV pair requires one read to disk, overwriting a KV pair requires one read and one write, inserting requires two reads and two writes, and deleting requires two reads and one write. What’s more, the writes are appending, which is very SSD-friendly. Experiments show that MoeingADS is even faster than LevelDB. The cost is the larger consumption of DRAM: Each key-value pair demands about 16 bytes.
* MoeingDB: MoeingDB is an application-specific database that stores blockchain history. It was developed with blockchain characteristics in mind which enables it to suit a blockchain's workload best. Based on its features, an open-source, high-QPS Web3 API can be built, benefiting both Smart Bitcoin Cash and Ethereum.
* MoeingKV: MoeingKV is a KV storage module much faster than LevelDB in reading and writing, at the cost of removing iteration support. In underlying data structure design and code implementation, MoeingKV produces trade-offs and optimizations to speed up normal read and write operations. It can be used to store the UTXO set of Bitcoin Cash.
* MoeingAOT: MoeingAOT is an ahead-of-time compiler for EVM. MoeingAOT can compile EVM bytecode into native code, which would consequently be saved as a dynamically linked library. When the EVM interpreter starts running a smart contract and finds its corresponding compiled library file, the library will be loaded, and bytecode interpretation won't be necessary.

We have also performed feasibility research on two extra libraries (MoeingRollup and MoeingLink), which can further scale up Smart Bitcoin Cash in the long run.

### Q: Does smartBCH interoperate with Ethereum?

Currently smartBCH does not directly interoperate with Ethereum, but in time a gateway may bridge assets between them. In the future, bridges based on smart contracts are also possible, with a scheme similar to [rainbow bridge](https://near.org/blog/eth-near-rainbow-bridge/).

### Q: Does smartBCH have to modify Solidity to deal with a UXTO model rather than regular ETH wallet balances?

SmartBCH, like Ethereum, uses an account model instead of a UTXO model.

### Q: Can I run any language that targets the EVM (like Vyper) on smartBCH or only specially modified languages?

It can use any language which compiles to EVM bytecode.

### Q: Can the validator who proposes the current block decide the order of transactions?

No. Unlike Ethereum, smartBCH reorders transactions in a pseudorandom way to mitigate the problem of front-running, which makes it much harder for a validator to enforce its preferred transaction order. Besides, smartBCH also reorders transactions to maximize parallelism.

### Q: What's smartBCH's consensus model, and how does it synchronize with Bitcoin Cash consensus?

SmartBCH uses a hybrid consensus model. It adopts Tendermint as its consensus engine. The quorum of validators is elected by both hash power and BCH owners, and it takes on duties in epochs.

An epoch contains 2,016 blocks (about two weeks). During an epoch, BCH owners prove their ownership of time-locked UTXOs and use the value of those UTXOs to vote for validators; whereas mining pools use coinbase transactions to vote. This is a hybrid consensus model: proof of hash power and stakes. The voting process takes place on Bitcoin Cash's mainnet and is totally permissionless because validators only needs endorsements from miners and/or holders.

An epoch's end time is the largest timestamp of its blocks, and its duration time is the difference between the end times of adjacent epochs. The quorum elected during an epoch will stay in a stand-by state for about 5% of the epoch's duration time. Then it takes its turn to be on duty until the next quorum leaves its stand-by state. This is necessary because any Bitcoin Cash reorganization may alter the blocks in an epoch.

Each validator must pledge some BCH as collateral, which would be slashed should it misbehave during its duty.

At the first phase after Smart Bitcoin Cash's launch, only hash power is used for electing validators. Locking BCH at mainnet for staking will be implemented later and will take effect in a future hard fork.

### Q: How does one become a validator?

At smartBCH's launch, the voting mechanism of "one block, one vote" will be adopted. That is, in the 2,016 blocks during an epoch, each mining pool will get one vote for every Bitcoin Cash block mined to vote on the smartBCH validators. You don't need to submit any application for becoming a validator. It is only necessary to have adequate computing power and receive votes from Bitcoin Cash miners and later BCH holders.

### Q: Will there be an ICO for smartBCH Coin?

There is no ICO and no smartBCH Coin. Smart Bitcoin Cash will not introduce new tokens. Its native token is BCH, and its gas fees are paid in BCH. There will be a gateway to transfer BCH to the smartBCH Chain as a gas token.

### Q: How will the gateway be realized between Bitcoin Cash mainnet and smartBCH?

The gateway between Bitcoin Cash mainnet and smartBCH will start as a PoA gateway and we will continue to improve its functionality and precision. The optimized solution may not be like any existing solutions used by RSK, Liquid, ETH2.0, Cosmos, or Polkadot. Instead, it must fit into Bitcoin Cash's infrastructure. After adding introspection opcodes, covenants will be much easier to implement on Bitcoin Cash, and we will very likely use them.

### Q: What are the advantages for developers building their DeFi protocols on smartBCH?

The most crucial advantage for building DeFi protocols on smartBCH is the inexpensive transaction fees. The demand for more ETH and Ethereum's ability to execute smart contracts is why its gas fees remain high. However, smartBCH will utilize extremely high throughput to make sure the transaction fees are inexpensive even with a large userbase.

### Q: What does the throughput of smartBCH look like right now?

Limited tests currently show that the underlying storage engine can support more than 600 times the throughput of Ethereum. However, there are still many factors to consider when running the whole chain, and there will be some challenges we might face. We hope that within 20 months, the throughput per second will be 100 times larger than ETH1.0. When smartBCH initially launches, we estimate a throughput 10-20 times larger than ETH1.0.


# Mainnet

This document introduces how to join the mainnet of smartBCH as a normal node (non-validator node).

Before you start, you must have a trusted server running bitcoincashnode's client with RPC enabled. The executable `smartbchd` will connect to it for querying staking information.

First, build the latest binary by running the steps of [this document](https://github.com/smartbch/docs/blob/master/developers-guide/build-smartbchd.md).

Second, prepare the working directory:

```bash
cp ~/smart_bch/smartbch/smartbchd ~/build/smartbchd
cd ~
rm -rf .smartbchd
~/build/smartbchd init mynode --chain-id 0x2710
wget https://github.com/smartbch/artifacts/releases/download/v0.0.6/dot.smartbchd.tgz
tar zxvf dot.smartbchd.tgz
cp -rf dot.smartbchd/* .smartbchd/
```

Third, open the `~/.smartbchd/config/app.toml` file to modify the information of the bitcoincashnode's client with RPC enabled.

```
# BCH mainnet rpc url (Only BCHN & BCHD are well tested)
mainnet-rpc-url = "http://ip-address:8332"

# BCH mainnet rpc username
mainnet-rpc-username = "<my user name>"

# BCH mainnet rpc password
mainnet-rpc-password = "<my password>"
```

Last, start smartbchd.

```bash
cd ~/build
./smartbchd start --mainnet-genesis-height=698502
```

## Docker

You can also run your smartBCH node using Docker. First, clone smartBCH and build Docker image for mainnet (or [pull prebuilt images from DockerHub](https://hub.docker.com/r/smartbch/smartbchd/tags)):

```bash
git clone https://github.com/smartbch/smartbch.git
cd smartbch
docker image build -f Dockerfile.optimized -t smartbchd:latest .
```

Second, prepare smartBCH mainnet home directory:

```bash
cd somewhere
mkdir smartbchd_home
docker run \
  -v path/to/smartbchd_home:/root/.smartbchd \
  smartbchd:latest init mynode --chain-id 0x2710

wget https://github.com/smartbch/artifacts/releases/download/v0.0.6/dot.smartbchd.tgz
tar xvf dot.smartbchd.tgz
cp -rfv dot.smartbchd/* smartbchd_home/
```

Third, edit smartbchd\_home/config/app.toml, modify the information of the bitcoincashnode's client:

```toml
...
mainnet-rpc-url = "http://ip-address:8332" # BCH mainnet rpc url
mainnet-rpc-username = "<my user name>"    # BCH mainnet rpc username
mainnet-rpc-password = "<my password>"     # BCH mainnet rpc password
...
```

Last, start smartbchd using Docker like this:

```bash
docker run \
  -v path/to/smartbchd_home:/root/.smartbchd \
  -p 0.0.0.0:8545:8545 \
  -p 0.0.0.0:8546:8546 \
  -p 0.0.0.0:26656:26656 \
  --ulimit nofile=65535:65535 \
  --log-opt max-size=200m \
  -d smartbchd:latest start --mainnet-genesis-height=698502
```


# Testnets

You can test your DApp using a [local single-node testnet](/smartbch/archives/runsinglenode) if you want to set one up. In most cases, though, you might not need to set up a testnet yourself. Instead, you can using an existing testnet. Here are the running testnets you can utilize.

You can run tests with [metamask](/smartbch/archives/test-using-metamask), [truffle](/smartbch/developers-guide/deploy-contract-using-truffle), or [remix](/smartbch/developers-guide/deploy-contract-using-remix).

### The Amber Testnet

This is a testnet for smartBCH with votes from a BCHN testnet, which has a bitcoincashnode client which mines with CPU.The chain ID is 0x2711. You can use the following JSON-RPC nodes:

1. <http://35.220.203.194:8545>
2. <https://moeing.tech:9545>

Test coin faucet can be found at <http://13.214.162.63:8080/faucet> or <http://moeing.tech:8080/faucet>

We sincerely thank [Allen Day](https://github.com/allenday) for donating several cloud servers to bring up this testnet.

In this testnet, the gas price can be as low as 0.2Gwei.

To join this testnet as a non-validator node, follow the steps below:

First, build the latest binary by running the steps of [this document](https://github.com/smartbch/docs/blob/master/developers-guide/build-smartbchd.md).

Second, clone & build smartbch:

```bash
cd ~/smart_bch
git clone -b v0.4.2 --depth 1 https://github.com/smartbch/smartbch
cd smartbch
go build -tags "params_amber cppbtree" github.com/smartbch/smartbch/cmd/smartbchd
```

Third, prepare the working directory:

```bash
cp ~/smart_bch/smartbch/smartbchd ~/build/smartbchd
cd ~
rm -rf .smartbchd
~/build/smartbchd init mynode --chain-id 0x2711
wget https://github.com/smartbch/artifacts/releases/download/v0.0.5/dot.smartbchd.tgz
tar zxvf dot.smartbchd.tgz
cp -rf dot.smartbchd/* .smartbchd/
```

Last, start smartbchd.

```bash
~/build/smartbchd start --mainnet-genesis-height=602983
```

Then you can join the testnet as a non-validator. If want to become a validator, please follow [this guide](/smartbch/testnets_validator).

If you want to join the underlying BCH testnet, here is the configuration file for bitcoincashnode:

```
regtest=1

[regtest]

bind=0.0.0.0
port=8331
rpcbind=0.0.0.0
rpcport=8332

zmqpubhashtx=tcp://0.0.0.0:8333
zmqpubhashblock=tcp://0.0.0.0:8333

rpcuser=test
rpcpassword=test
rpcthreads=4

rpcallowip=0.0.0.0/0

whitelistrelay=0

addnode=47.115.171.70:28331
```

## Docker

You can also run your smartBCH testnet node using Docker. First, clone smartBCH and build Docker image for testnet (or [pull prebuilt images from DockerHub](https://hub.docker.com/r/smartbch/smartbchd/tags)):

```bash
git clone https://github.com/smartbch/smartbch.git
cd smartbch
docker image build -f Dockerfile.optimized \
	--build-arg SMARTBCH_BUILD_TAGS='cppbtree,params_amber' \
	--build-arg SMARTBCH_VERSION=v0.4.2 \
	--build-arg CONFIG_VERSION=v0.0.4 \
	--build-arg CHAIN_ID=0x2711 \
	-t smartbchd-amber:latest .
```

Second, prepare smartBCH testnet home directory:

```bash
cd somewhere
mkdir smartbchd_home
docker run \
  -v path/to/smartbchd_home:/root/.smartbchd \
  smartbchd:latest init mynode --chain-id 0x2711

wget https://github.com/smartbch/artifacts/releases/download/v0.0.4/dot.smartbchd.tgz
tar xvf dot.smartbchd.tgz
cp -rfv dot.smartbchd/* smartbchd_home/
```

Last, start smartbchd using Docker like this:

```bash
docker run \
  -v path/to/smartbchd_home:/root/.smartbchd \
  -p 0.0.0.0:18545:8545 \
  -p 0.0.0.0:18546:8546 \
  --ulimit nofile=65535:65535 \
  -d smartbchd-amber:latest start --mainnet-genesis-height=602983
```


# Join Amber testnet as a Validator

This document introduces how to join the amber as a validator node.

Before you start, you must have a trusted server running bitcoincashnode's client with RPC enabled. The executable `smartbchd` will connect to it for querying staking information.

#### 1. build the binary

Running the steps of [this document](https://github.com/smartbch/docs/blob/master/developers-guide/build-smartbchd.md).

Then clone the source code of smartBCH and build the executable of `smartbchd`.

```bash
cd ~/smart_bch
git clone -b v0.4.2 --depth 1 https://github.com/smartbch/smartbch
cd smartbch
go build -tags "params_amber cppbtree" github.com/smartbch/smartbch/cmd/smartbchd
```

After successfully executing the above commands, you'll get a \~/smart\_bch/smartbch/smartbchd file for amber.

#### 2. prepare the working directory

```bash
cp ~/smart_bch/smartbch/smartbchd ~/build/smartbchd
cd ~
rm -rf .smartbchd
~/build/smartbchd init mynode --chain-id 0x2711
wget https://github.com/smartbch/artifacts/releases/download/v0.0.5/dot.smartbchd.tgz
tar zxvf dot.smartbchd.tgz
cp -rf dot.smartbchd/* .smartbchd/
```

#### 3. Prepare the validator keys

Running step 1 and step 2 of [this doc](/smartbch/archives/runmultinode#1-on-the-nodes-which-do-not-generate-the-genesis-file) to generate validator key and consensus pubkey.

Then, copy the priv\_validator\_key.json to work directory by running command below:

```
cp ./priv_validator_key.json ~/.smartbchd/config/
```

#### 4. Modify App config

Open the `~/.smartbchd/config/app.toml` file to modify the information of the bitcoincashnode's client with RPC enabled.

```
# BCH mainnet rpc url
mainnet-rpc-url = "http://ip-address:8332"

# BCH mainnet rpc username
mainnet-rpc-username = "<my user name>"

# BCH mainnet rpc password
mainnet-rpc-password = "<my password>"
```

#### 5. start smartbchd

```bash
cd ~/build
~/build/smartbchd start --mainnet-genesis-height=602983
```

#### 6. Build createValidator Tx

Using validator private key and consensus pubkey generated in step 3 to build command below:

```
./smartbchd staking \
--validator-key=<your validator private key> \
--staking-coin=1 \
--consensus-pubkey=<your consensus pub key> \
--introduction=<your validator introduction> \
--type=create \
--nonce=0 \
--gas-price=10000000000 \
--chain-id=0x2711	
```

This command generate createValidator tx raw data, send it in step 8 below.

#### 7. Get some BCH to Send Tx

Get some BCH from some one has BCH in smartBCH already to your validator account. To check your account balance like this.

```
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["<your validator account address>","latest"],"id":1}' -H "Content-Type: application/json" http://127.0.0.1:8545
```

#### 8. Send Tx to smartBCH Amber

Please follow step 1, 2 of [this doc](/smartbch/archives/runmultinode#step-1-send-transaction-to-register-as-a-validator).

#### 9. Vote your consensus pubkey in Amber Xhedge Contract

Please go to <https://amber.xhedge.cash/> to split your BCH to LeverNFT and HedgeNFT, and vote for your validator just created.


# Introduction

Currently, there are no toolkits dedicatedly designed for smartBCH. Please use the tools from Ethereum's ecosystem (Remix, truffle, waffle, ganache, etc) to develop the source code and compile the EVM bytecode. After the DApp works fine on ganache, you can start testing it with smartbchd (the executable of smartBCH's full node client), which can [start a single node private testnet](/smartbch/archives/runsinglenode), or a [multi-node testnet](/smartbch/archives/runmultinode)

Through a compatible Web3 API, smartbchd interacts with the wallets (such as MetaMask) and DApp's backend, just as an infura node does. We try our best to make it behave the same as infura for compatibility, but there are still missing features and bugs.

For a list of supported RPC endpoints, please see [here](/smartbch/developers-guide/jsonrpc).

We also provide a [backend design](https://github.com/smartbch/BasicExplorer/tree/main/backend) of blockchain explorer for smartBCH. It just has basic functions and is not so powerful as etherscan. If you wants to add a frontend to build a complete explorer, this [API document](https://github.com/smartbch/docs/blob/master/developers-guide/browserapi.md) may help you.

If you find a mistake in the document, please tell us by create an issue at <https://github.com/smartbch/docs/issues>. If a missing feature blocks you, we are sorry but you need to modify your application to bypass it.


# Deploy contracts using Truffle

This article takes [Pet-Shop](https://www.trufflesuite.com/tutorial) as an example to introduce how to deploy smart contract into smartBCH testnet using [truffle](https://www.trufflesuite.com/truffle).

## Build smartbchd and generate a test key

Please flow [this document](https://github.com/smartbch/docs/blob/master/developers-guide/build-smartbchd.md) to clone and build `smartbchd`. We need a test account and associated private key, `smartbchd` provides a sub-command to generate them for us:

```bash
$ cd path/to/your/smartbch/dir # and build smartbchd following the given doc
$ ./smartbchd gen-test-keys -n 1 --show-address
```

The output looks like this (the generated private key and address are seperated by a space):

```
09c57df30208bdc056144c32d607f0719bdb0f8ac5f0a3259720d9e4d28d999b 0xab83b691Bc12Aae947B2ca240F1732fa792dE246
```

Go to [smartBCH testnet faucet](http://54.169.31.93:8080/faucet) to fund our newly generated address some BCH.

## Install Truffle

We need to install Node.js first, [here](https://nodejs.org/en/download/package-manager/) are detailed information about how to install it on various platforms. Then, run the following cmd to install truffle:

```bash
$ npm install -g truffle
```

And run the following cmd the see if truffle was installed successfully:

```bash
$ truffle version

Truffle v5.1.63 (core: 5.1.63)
Solidity v0.5.16 (solc-js)
Node v15.10.0
Web3.js v1.2.9
```

## Clone Pet-Shop and add testnet config

Using `git clone` cmd to clone pet-shop source code into you local directory:

```bash
$ cd somedir
$ git clone https://github.com/trufflesuite/pet-shop-tutorial.git
$ cd pet-shop-tutorial
```

Install [truffle hdwallet-provider](https://www.npmjs.com/package/@truffle/hdwallet-provider) v1.2.6 (for some unknown reason, the latest version v1.3.x may not work with private keys, so we use v1.2.x here):

```bash
$ npm install @truffle/hdwallet-provider@1.2.6 --save-dev
```

Modify truffle-config.js, add smartBCH testnet network configuration using you test key like bellow (you can find more smartBCH testnet RPC URLs [here](/smartbch/testnets)):

```javascript
const HDWalletProvider = require('@truffle/hdwallet-provider');

module.exports = {
  // See <http://truffleframework.com/docs/advanced/configuration>
  // for more about customizing your Truffle configuration!
  networks: {
    development: {
      host: "127.0.0.1",
      port: 7545,
      network_id: "*" // Match any network id
    },
    sbch_testnet: {
      network_id: "10001",
      gasPrice: 0,
      provider: () => new HDWalletProvider({
        providerOrUrl: "http://35.220.203.194:8545",
        privateKeys: [
          "09c57df30208bdc056144c32d607f0719bdb0f8ac5f0a3259720d9e4d28d999b",
        ],
      }),
    }
  }
};
```

## Deploy Pet-Shop to smartBCH testnet

In directory pet-shop-tutorial, using `truffle migrate` cmd to deploy Pet-Shop contract into smartBCH testnet:

```bash
$ truffle migrate --network sbch_testnet
```

The output looks like this:

```
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.



Starting migrations...
======================
> Network name:    'sbch_testnet'
> Network id:      10001
> Block gas limit: 200000000 (0xbebc200)


1_initial_migration.js
======================

   Deploying 'Migrations'
   ----------------------
   > transaction hash:    0xd03a612ec8ff3800fdaba8eab70230575cf5b6ed9c1eeecfa5595b20d7553281
   > Blocks: 1            Seconds: 8
   > contract address:    0x12033fAFdd217E1fF8F247D9C6E9a0606f75c813
   > block number:        71514
   > block timestamp:     1619962004
   > account:             0xab83b691Bc12Aae947B2ca240F1732fa792dE246
   > balance:             0.01
   > gas used:            225225 (0x36fc9)
   > gas price:           0 gwei
   > value sent:          0 ETH
   > total cost:          0 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:                   0 ETH


2_deploy_contracts.js
=====================

   Deploying 'Adoption'
   --------------------
   > transaction hash:    0xc5137d30a6b065bfac3b6a3b8a321ffc338366c110e56315f9e601bca56e344b
   > Blocks: 2            Seconds: 8
   > contract address:    0x7D268085bDa90c0F9bC1c16c5bE6632958470B89
   > block number:        71518
   > block timestamp:     1619962024
   > account:             0xab83b691Bc12Aae947B2ca240F1732fa792dE246
   > balance:             0.01
   > gas used:            203827 (0x31c33)
   > gas price:           0 gwei
   > value sent:          0 ETH
   > total cost:          0 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:                   0 ETH


Summary
=======
> Total deployments:   2
> Final cost:          0 ETH
```

Wow! You have deployed Pet-Shop into smartBCH testnet. Thank you for testing smartBCH testnet 😊


# Deploy contracts using Remix

This article shows how to deploy smart contract into smartBCH testnet using Remix IDE.

Step 0, add smartBCH testnet into MetaMask. You can find smartBCH testnet configuration on [chainlist](https://chainlist.org/en):

![chainlist](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWmt0o30W7ixggmDAgb%2Fuploads%2Fgit-blob-6c01649db6a1c7d8d61a8957e4e4f9470996f0e8%2Ftestnet-chainlist.png?alt=media)

Step 1, open [Remix IDE](http://remix.ethereum.org/) in your browser:

![remix](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWmt0o30W7ixggmDAgb%2Fuploads%2Fgit-blob-b6b380960d67a43d6db2328232d76e66f269d866%2Fremix.png?alt=media)

Step 2, chose an environment. We can use MetaMask by selecting "Injected Web3" or connect to node directly by selecting "Web3 Provider". Select "Injected Web3" to connect to MetaMask:

![remix-metamask-connect.png](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWmt0o30W7ixggmDAgb%2Fuploads%2Fgit-blob-8893549099499d88f54e0179a049711a412da479%2Fremix-metamask-connect.png?alt=media)

Step 3, create and compile your smart contract. We use Remix's Storage demo as example:

![remix-contract](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWmt0o30W7ixggmDAgb%2Fuploads%2Fgit-blob-dcc9a8415cdbfd5c69452dd1e41590b2b50f949f%2Fremix-contract.png?alt=media)

Compile your smart contract:

![image-20210414163154021](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWmt0o30W7ixggmDAgb%2Fuploads%2Fgit-blob-09127389b27b08237daecde1f1d5b9b131196725%2Fremix-compile.png?alt=media)

Step 4, deploy compiled smart contract by clicking "Deploy" button:

![image-20210414163757696](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWmt0o30W7ixggmDAgb%2Fuploads%2Fgit-blob-0e116e74b9f417205f9268e942ada6bfdaff881a%2Fremix-metamask-deploy.png?alt=media)

Click "Confirm" button on MetaMask popup window:

![remix-metamask-deploy2](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWmt0o30W7ixggmDAgb%2Fuploads%2Fgit-blob-bc444c227f7f371d78b1d7d3b81149b1af109720%2Fremix-metamask-deploy2.png?alt=media)


# JSON-RPC Endpoints

## JSON-RPC smartBCH

Here is a list of all the supported RPC endpoints of smartBCH, sorted by the prefixes. The endpoints with "sbch" prefix are smartBCH-specific, which are used by the [BasicBrowser](https://github.com/smartbch/BasicBrowser). The endpoints with "web3", "net" and "eth" prefixes have the same function as infura, except for some features which are described below.

### Web3

| JSON-RPC methods    | Doc (eth.wiki)                                     | Doc (infura.io/docs)                                          | Implemented? |
| ------------------- | -------------------------------------------------- | ------------------------------------------------------------- | ------------ |
| web3\_clientVersion | <https://eth.wiki/json-rpc/API#web3_clientVersion> | <https://infura.io/docs/ethereum/json-rpc/web3-clientVersion> | ✅            |
| web3\_sha3          | <https://eth.wiki/json-rpc/API#web3_sha3>          |                                                               | ✅            |

### Net

| JSON-RPC methods | Doc (eth.wiki)                                | Doc (infura.io/docs)                                     | Implemented? |
| ---------------- | --------------------------------------------- | -------------------------------------------------------- | ------------ |
| net\_version     | <https://eth.wiki/json-rpc/API#net_version>   | <https://infura.io/docs/ethereum/json-rpc/net-version>   | ✅            |
| net\_peerCount   | <https://eth.wiki/json-rpc/API#net_peercount> | <https://infura.io/docs/ethereum/json-rpc/net-peerCount> | ❌            |
| net\_listening   | <https://eth.wiki/json-rpc/API#net_listening> | <https://infura.io/docs/ethereum/json-rpc/net-listening> | ❌            |

### ETH

⚠️the ['pending' block number parameter](https://eth.wiki/json-rpc/API#the-default-block-parameter) is not supported, because the mempool of smartbchd is invisable now.

The throughput of smartBCH is very high, and no transactions will be waiting in the mempool for a long time, so there is no need to check whether a transaction is accepted by mempool.

| JSON-RPC methods                         | Doc (eth.wiki)                                                          | Doc (infura.io/docs)                                                               | Implemented?  |
| ---------------------------------------- | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------- |
| eth\_protocolVersion                     | <https://eth.wiki/json-rpc/API#eth_protocolversion>                     | <https://infura.io/docs/ethereum/json-rpc/eth-protocolVersion>                     | ✅             |
| eth\_syncing                             | <https://eth.wiki/json-rpc/API#eth_syncing>                             | <https://infura.io/docs/ethereum/json-rpc/eth-syncing>                             | ✅             |
| eth\_coinbase                            | <https://eth.wiki/json-rpc/API#eth_coinbase>                            |                                                                                    | ✅ (returns 0) |
| eth\_mining                              | <https://eth.wiki/json-rpc/API#eth_mining>                              | <https://infura.io/docs/ethereum/json-rpc/eth-mining>                              | ❌             |
| eth\_hashrate                            | <https://eth.wiki/json-rpc/API#eth_hashrate>                            | <https://infura.io/docs/ethereum/json-rpc/eth-hashrate>                            | ❌             |
| eth\_gasPrice                            | <https://eth.wiki/json-rpc/API#eth_gasprice>                            | <https://infura.io/docs/ethereum/json-rpc/eth-gasPrice>                            | ✅ (returns 0) |
| eth\_accounts                            | <https://eth.wiki/json-rpc/API#eth_accounts>                            | <https://infura.io/docs/ethereum/json-rpc/eth-accounts>                            | ✅             |
| eth\_blockNumber                         | <https://eth.wiki/json-rpc/API#eth_blocknumber>                         | <https://infura.io/docs/ethereum/json-rpc/eth-blockNumber>                         | ✅             |
| eth\_getBalance                          | <https://eth.wiki/json-rpc/API#eth_getbalance>                          | <https://infura.io/docs/ethereum/json-rpc/eth-getBalance>                          | ✅ ❌pending    |
| eth\_getStorageAt                        | <https://eth.wiki/json-rpc/API#eth_getstorageat>                        | <https://infura.io/docs/ethereum/json-rpc/eth-getStorageAt>                        | ✅ ❌pending    |
| eth\_getTransactionCount                 | <https://eth.wiki/json-rpc/API#eth_gettransactioncount>                 | <https://infura.io/docs/ethereum/json-rpc/eth-getTransactionCount>                 | ✅ ❌pending    |
| eth\_getBlockTransactionCountByHash      | <https://eth.wiki/json-rpc/API#eth_getblocktransactioncountbyhash>      | <https://infura.io/docs/ethereum/json-rpc/eth-getBlockTransactionCountByHash>      | ✅             |
| eth\_getBlockTransactionCountByNumber    | <https://eth.wiki/json-rpc/API#eth_getblocktransactioncountbynumber>    | <https://infura.io/docs/ethereum/json-rpc/eth-getBlockTransactionCountByNumber>    | ✅ ❌pending    |
| eth\_getUncleCountByBlockHash            | <https://eth.wiki/json-rpc/API#eth_getunclecountbyblockhash>            | <https://infura.io/docs/ethereum/json-rpc/eth-getUncleCountByBlockHash>            | ❌             |
| eth\_getUncleCountByBlockNumber          | <https://eth.wiki/json-rpc/API#eth_getunclecountbyblocknumber>          | <https://infura.io/docs/ethereum/json-rpc/eth-getUncleCountByBlockNumber>          | ❌             |
| eth\_getCode                             | <https://eth.wiki/json-rpc/API#eth_getcode>                             | <https://infura.io/docs/ethereum/json-rpc/eth-getCode>                             | ✅ ❌pending    |
| eth\_sign                                | <https://eth.wiki/json-rpc/API#eth_sign>                                |                                                                                    | ❌             |
| eth\_signTransaction                     | <https://eth.wiki/json-rpc/API#eth_signtransaction>                     |                                                                                    | ❌             |
| eth\_sendTransaction                     | <https://eth.wiki/json-rpc/API#eth_sendtransaction>                     |                                                                                    | ✅             |
| eth\_sendRawTransaction                  | <https://eth.wiki/json-rpc/API#eth_sendrawtransaction>                  | <https://infura.io/docs/ethereum/json-rpc/eth-sendRawTransaction>                  | ✅             |
| eth\_call                                | <https://eth.wiki/json-rpc/API#eth_call>                                | <https://infura.io/docs/ethereum/json-rpc/eth-call>                                | ✅ ❌pending    |
| eth\_estimateGas                         | <https://eth.wiki/json-rpc/API#eth_estimategas>                         | <https://infura.io/docs/ethereum/json-rpc/eth-estimateGas>                         | ✅             |
| eth\_getBlockByHash                      | <https://eth.wiki/json-rpc/API#eth_getblockbyhash>                      | <https://infura.io/docs/ethereum/json-rpc/eth-getBlockByHash>                      | ✅             |
| eth\_getBlockByNumber                    | <https://eth.wiki/json-rpc/API#eth_getblockbynumber>                    | <https://infura.io/docs/ethereum/json-rpc/eth-getBlockByNumber>                    | ✅ ❌pending    |
| eth\_getTransactionByHash                | <https://eth.wiki/json-rpc/API#eth_gettransactionbyhash>                | <https://infura.io/docs/ethereum/json-rpc/eth-getTransactionByHash>                | ✅             |
| eth\_getTransactionByBlockHashAndIndex   | <https://eth.wiki/json-rpc/API#eth_gettransactionbyblockhashandindex>   | <https://infura.io/docs/ethereum/json-rpc/eth-getTransactionByBlockHashAndIndex>   | ✅             |
| eth\_getTransactionByBlockNumberAndIndex | <https://eth.wiki/json-rpc/API#eth_gettransactionbyblocknumberandindex> | <https://infura.io/docs/ethereum/json-rpc/eth-getTransactionByBlockNumberAndIndex> | ✅ ❌pending    |
| eth\_getTransactionReceipt               | <https://eth.wiki/json-rpc/API#eth_gettransactionreceipt>               | <https://infura.io/docs/ethereum/json-rpc/eth-getTransactionReceipt>               | ✅             |
| eth\_getUncleByBlockHashAndIndex         | <https://eth.wiki/json-rpc/API#eth_getunclebyblockhashandindex>         | <https://infura.io/docs/ethereum/json-rpc/eth-getUncleByBlockHashAndIndex>         | ❌             |
| eth\_getUncleByBlockNumberAndIndex       | <https://eth.wiki/json-rpc/API#eth_getunclebyblocknumberandindex>       | <https://infura.io/docs/ethereum/json-rpc/eth-getUncleByBlockNumberAndIndex>       | ❌             |
| eth\_getCompiles                         | <https://eth.wiki/json-rpc/API#eth_getcompilers>                        |                                                                                    | ❌             |
| eth\_compileLLL                          | <https://eth.wiki/json-rpc/API#eth_compilelll>                          |                                                                                    | ❌             |
| eth\_compileSolidity                     | <https://eth.wiki/json-rpc/API#eth_compilesolidity>                     |                                                                                    | ❌             |
| eth\_compileSerpent                      | <https://eth.wiki/json-rpc/API#eth_compileserpent>                      |                                                                                    | ❌             |
| eth\_newFilter                           | <https://eth.wiki/json-rpc/API#eth_newfilter>                           | <https://infura.io/docs/ethereum/json-rpc/eth-newFilter>                           | ✅ ❌pending    |
| eth\_newBlockFilter                      | <https://eth.wiki/json-rpc/API#eth_newblockfilter>                      | <https://infura.io/docs/ethereum/json-rpc/eth-newBlockFilter>                      | ✅             |
| eth\_newPendingTransactionFilter         | <https://eth.wiki/json-rpc/API#eth_newpendingtransactionfilter>         |                                                                                    | ✅             |
| eth\_uninstallFilter                     | <https://eth.wiki/json-rpc/API#eth_uninstallfilter>                     | <https://infura.io/docs/ethereum/json-rpc/eth-uninstallFilter>                     | ✅             |
| eth\_getFilterChanges                    | <https://eth.wiki/json-rpc/API#eth_getfilterchanges>                    | <https://infura.io/docs/ethereum/json-rpc/eth-getFilterChanges>                    | ✅             |
| eth\_getFilterLogs                       | <https://eth.wiki/json-rpc/API#eth_getfilterlogs>                       |                                                                                    | ✅             |
| eth\_getLogs                             | <https://eth.wiki/json-rpc/API#eth_getlogs>                             | <https://infura.io/docs/ethereum/json-rpc/eth-getLogs>                             | ✅ ❌pending    |
| eth\_getWork                             | <https://eth.wiki/json-rpc/API#eth_getwork>                             | <https://infura.io/docs/ethereum/json-rpc/eth-getWork>                             | ❌             |
| eth\_submitWork                          | <https://eth.wiki/json-rpc/API#eth_submitwork>                          | <https://infura.io/docs/ethereum/json-rpc/eth-submitWork>                          | ❌             |
| eth\_submitHashrate                      | <https://eth.wiki/json-rpc/API#eth_submithashrate>                      | <https://infura.io/docs/ethereum/json-rpc/eth-hashrate>                            | ❌             |
| eth\_chainId                             |                                                                         | <https://infura.io/docs/ethereum/json-rpc/eth-chainId>                             | ✅             |
| eth\_subscribe                           |                                                                         | <https://infura.io/docs/ethereum/wss/eth-subscribe>                                |               |
| eth\_unsubscribe                         |                                                                         | <https://infura.io/docs/ethereum/wss/eth-unsubscribe>                              |               |

### Txpool (non-standard)

| JSON-RPC methods | Doc                                                             | Implemented?           |
| ---------------- | --------------------------------------------------------------- | ---------------------- |
| txpool\_content  | <https://geth.ethereum.org/docs/rpc/ns-txpool#txpool\\_content> | ✅ (returns empty data) |
| txpool\_status   | <https://geth.ethereum.org/docs/rpc/ns-txpool#txpool\\_status>  | ✅ (returns empty data) |
| txpool\_inspect  | <https://geth.ethereum.org/docs/rpc/ns-txpool#txpool\\_inspect> | ✅ (returns empty data) |

## SBCH

| JSON-RPC methods                                                     | Doc (eth.wiki) | Doc (infura.io/docs) | Since  |
| -------------------------------------------------------------------- | -------------- | -------------------- | ------ |
| [sbch\_queryTxBySrc](#sbch_queryTxBySrc)                             | N/A            | N/A                  | v0.1.0 |
| [sbch\_queryTxByDst](#sbch_queryTxByDst)                             | N/A            | N/A                  | v0.1.0 |
| [sbch\_queryTxByAddr](#sbch_queryTxByAddr)                           | N/A            | N/A                  | v0.1.0 |
| [sbch\_queryLogs](#sbch_queryLogs)                                   | N/A            | N/A                  | v0.1.0 |
| [sbch\_getTxListByHeight](#sbch_getTxListByHeight)                   | N/A            | N/A                  | v0.1.0 |
| [sbch\_getTxListByHeightWithRange](#sbch_getTxListByHeightWithRange) | N/A            | N/A                  | v0.1.0 |
| [sbch\_getAddressCount](#sbch_getAddressCount)                       | N/A            | N/A                  | v0.1.0 |
| [sbch\_getSep20AddressCount](#sbch_getSep20AddressCount)             | N/A            | N/A                  | v0.2.0 |
| [sbch\_getTransactionReceipt](#sbch_getTransactionReceipt)           | N/A            | N/A                  | v0.4.0 |
| [sbch\_validatorsInfo](#sbch_validatorsInfo)                         | N/A            | N/A                  | V0.4.1 |

### sbch\_queryTxBySrc

Returns the information about transactions requested by sender address and block range.

Parameters:

1. `DATA`, 20 Bytes - from address
2. `QUANTITY` - integer, start number
3. `QUANTITY` - integer, end number
4. `QUANTITY` - integer, the maximal number of txs to return, `0` stands for default limit

Note: the start number can be greater than the end number, if so, the results will be sorted by block height in descending order.

Retrns:

`Array` - array of transaction objects, see [eth\_getTransactionByHash](https://eth.wiki/json-rpc/API#eth_getTransactionByHash)

### sbch\_queryTxByDst

Returns the information about transactions requested by recipient address and block range.

Parameters:

1. `DATA`, 20 Bytes - to address
2. `QUANTITY|TAG` - integer of start number, or string `"latest"` for the last mined block
3. `QUANTITY|TAG` - integer of end number, or string `"latest"` for the last mined block
4. `QUANTITY` - integer, the maximal number of txs to return, `0` stands for default limit

Note: the start number can be greater than the end number, if so, the results will be sorted by block height in descending order.

Retrns:

`Array` - array of transaction objects, see [eth\_getTransactionByHash](https://eth.wiki/json-rpc/API#eth_getTransactionByHash)

### sbch\_queryTxByAddr

Returns the information about transactions requested by address (sender or recipient) and block range.

Parameters:

1. `DATA`, 20 Bytes - from or to address
2. `QUANTITY|TAG` - integer of start number, or string `"latest"` for the last mined block
3. `QUANTITY|TAG` - integer of end number, or string `"latest"` for the last mined block
4. `QUANTITY` - integer, the maximal number of txs to return, `0` stands for default limit

Note: the start number can be greater than the end number, if so, the results will be sorted by block height in descending order.

Retrns:

`Array` - array of transaction objects, see [eth\_getTransactionByHash](https://eth.wiki/json-rpc/API#eth_getTransactionByHash)

### sbch\_queryLogs

Query logs by address, topics and block range. It is different from `eth_getLogs` in:

1. the contract address is required, not optional;
2. the topics are position-independent, which means as long as a log has the specified topics in any position, it will be included in the returned result.

Parameters:

1. `DATA`, 20 Bytes - contract address
2. `Array of DATA`, topics
3. `QUANTITY|TAG` - integer of start number, or string `"latest"` for the last mined block
4. `QUANTITY|TAG` - integer of end number, or string `"latest"` for the last mined block
5. `QUANTITY` - integer, the maximal number of txs to return, `0` stands for default limit.

Note: the start number can be greater than the end number, if so, the results will be sorted by block height in descending order.

Returns:

`Array` - array of log objects, see [eth\_getLogs](https://eth.wiki/json-rpc/API#eth_getLogs)

### sbch\_getTxListByHeight

Get tx list by height.

Parameters:

1. `QUANTITY|TAG` - integer of start number, or string `"latest"` for the last mined block

Returns:

`Array` - array of transaction objects, see [sbch\_getTransactionReceipt](#sbch_getTransactionReceipt)

### sbch\_getTxListByHeightWithRange

Get tx list by height and tx index range.

Parameters:

1. `QUANTITY|TAG` - integer of start number, or string `"latest"` for the last mined block
2. `QUANTITY` - integer of start tx index
3. `QUANTITY` - integer of end tx index, or "0x0" which stands for "the largest tx index"

Returns:

`Array` - array of transaction objects, see [sbch\_getTransactionReceipt](#sbch_getTransactionReceipt)

### sbch\_getAddressCount

Returns the times addr acts as a to-address or from-address of a transaction.

Parameters:

1. `String`, kind of the query, could be `"from"`, `"to"`, or `"both"`
2. `DATA`, 20 Bytes - EOA or contract address

Returns:

`QUANTITY` - integer of count

### sbch\_getSep20AddressCount

Returns the times addr acts as a to-address or from-address of a SEP20 Transfer event at some contract.

Parameters:

1. `String`, kind of the query, could be `"from"`, `"to"`, or `"both"`
2. `DATA`, 20 Bytes - SEP20 contract address
3. `DATA`, 20 Bytes - EOA or contract address

Returns:

`QUANTITY` - integer of count

### sbch\_getTransactionReceipt

Enhanced version of [eth\_getTransactionReceipt](https://eth.wiki/json-rpc/API#eth_getTransactionReceipt), the returned array of objects contain additional information about internal transactions.

Parameters: same as [eth\_getTransactionReceipt](https://eth.wiki/json-rpc/API#eth_getTransactionReceipt)

Returns: array of objects sepcified by [eth\_getTransactionReceipt](https://eth.wiki/json-rpc/API#eth_getTransactionReceipt) plus one more field of type Array: `internalTransactions`.

Each object in internalTransactions array contains the following fields:

* `callPath`: `string` - a string representation of call type, depth and index of internal transaction (e.g. staticcall\_0\_1\_1).
* `from`: `DATA`, 20 Bytes - address of the sender.
* `to`: `DATA`, 20 Bytes - address of the receiver.
* `gas`: `QUANTITY` - gas provided by the sender.
* `value`: `QUANTITY` - value transferred in Wei.
* `input`: `DATA` - the data send along with the internal transaction.
* `status`: `QUANTITY` - either `1` (success) or `0` (failure).
* `gasUsed`: `QUANTITY` - the amount of gas used by this internal transaction.
* `output`: `DATA` - the data returned by the internal transaction.
* `contractAddress`: `DATA`, 20 Bytes - The contract address created, if the transaction was a contract creation, otherwise `null`.

### sbch\_validatorsInfo

Returns the validators info.

Parameters: N/A

Returns: a validator info object:

* genesisMainnetBlockHeight: `QUANTITY` - The BCH mainnet height when smartbch chain mint genesis block.
* currEpochNum: `QUANTITY` - The epoch number of current epoch.
* validators: `Array` - Array of validator object, which mean validators created by call `stakingContract.createValidator` method.
* validatorsUpdate: `Array` - Array of validator object, which mean validators whose voting power updated when epoch switch.
* pendingRewards: `Array` - Array of pending rewards object, which mean validator pending rewards.
* minGasPrice: `QUANTITY` - The minimum gas price decided in current block.
* lastMinGasPrice: `QUANTITY` - The minimum gas price used in current block.
* currValidators: `Array` - Array of validator object, which mean validators who on duty in current epoch.

And the `validator` object has fields:

* address: `DATA`, 20 Bytes - Address of the validator.
* pubkey: `DATA`, 32 Bytes - Consensus pubkey of the validator.
* reward\_to: `DATA`, 20 Bytes - Address to receive block mint rewards.
* voting\_power: `QUANTITY` - The minimum gas price decided in current block.
* introduction: `String` - The introduction of validator.
* staked\_coins `DATA`, 32 Bytes - Staked coins of the validator.
* is\_retiring: `Boolean` - Indicate whether validator is retired.


# Staking Scheme

Smart Bitcoin Cash adopts [tendermint](https://github.com/tendermint/tendermint) as its consensus engine. The quorum of validators is elected only by Bitcoin Cash mainnet's hash power, and they take on duties in epochs. After the XHedge upgrade, both hash power and locked BCH can be used in elections.

### Epoch-based Validator Election

An epoch contains 2,016 blocks (takes about two weeks). During an epoch, mining pools use coinbase transactions to vote. This voting process is performed on Bitcoin Cash's mainnet and is totally permissionless because a new validator only needs endorsements from miners.

The voting protocol is simple: the first output of the coinbase transaction which meets the following requirement is regarded as a vote:

1. It begins with the "OP\_RETURN" opcode
2. The pushed value after OP\_RETURN is a 37-byte string, in which the starting 5 bytes are 0x73, 0x42, 0x43, 0x48, and 0x0, and the ending 32 bytes are an ed25519 public key, which is used to identify a node in tendermint

There may be multiple outputs meeting the above two requirements, but only the first one is regarded as a vote, and the others are ignored.

An epoch's end time is the largest timestamp of its blocks, and its duration time is the difference between the end times of adjacent epochs. The quorum elected during an epoch will stay in a standby state for 5% of the epoch's duration time. Then it takes its turn to be on duty until the next quorum leaves its standby state, which is necessary because any Bitcoin Cash reorganization may alter the blocks in an epoch.

After the XHedge upgrade, BCH holders on smartBCH can elect validators through the [XHedge smart contract](/smartbch/developers-guide/xhedge-contract) in a PoS scheme. The voting power from miners (PoW) and the voting power from BCH holders (PoS) are both 50%.

### Register as a Validator

Before being elected as a validator on duty, you must first register as a candidate validator, by sending transactions on smartBCH.

A special smart contract at the address 0x2710 handles transactions related to staking. It has several functions which can only be called from EOAs (externally owned accounts) and one function which can only be called by other smart contracts. It is implemented using native code and can do jobs that normal EVM contracts cannot do.

It's interface is as below:

```solidity
interface StakingContract {
    function createValidator(address rewardTo, bytes32 introduction, bytes32 pubkey) external;
    function editValidator(address rewardTo, bytes32 introduction) external;
    function retire() external;
    function increaseMinGasPrice() external;
    function decreaseMinGasPrice() external;
    function sumVotingPower(address[] calldata addrList) external override returns (uint summedPower, uint totalPower) // this function can only be called by other contracts
}
```

An EOA can call `createValidator` to register itself as a candidate validator and set the following parameters:

1. `rewardTo`, the account that receives the validator's reward
2. `introduction`, a short UTF8 string (no longer than 32 bytes) describing the validator, whose tailing bytes are zeros.
3. `pubkey`, an ed25519 pubkey for which the coinbase transactions' outputs can vote.

After becoming a candidate validator, an EOA cannot call `createValidator` again. Instead, it can use `editValidator` to change `rewardTo` and `introduction`, but the `pubkey` cannot be changed.

A validator must pledge some BCH as collateral, which would be slashed if it misbehaves during its duty. Once its pledged collateral is less than a lower bound because of slashing, its voting power is reduced to zero until enough collateral is replenished. A validator can pledge collateral by sending BCH when calling `createValidator` and `editValidator`.

If a validator no longer wants to act as a validator, it can call `retire` to mark its status as "retiring". The votes to a retiring validator is not counted when electing the next quorum.

### Query an Address Set's Voting Power

A smart contract can call the `sumVotingPower` function to sum all the voting power owned by the address set specified in `addrList`. It also returns the total voting power owned by all the active validators. These two parameters are returned as `summedPower` and `totalPower`, respectively.

A smart contract can record incoming votes from validators and use `sumVotingPower` to decide whether the votes are enough. In such a way, the validator set acts as Supreme Court to decide some cases finally.

### Adjust Gas Fee

Each validator can set its minimum acceptable gas price, which is respected in relaying transactions and receiving transactions into mempool. This parameter is not a consensus parameter.

The chain-wide minimum gas price is a consensus parameter, which is the lower bound of the minimum gas prices set by different validators. This consensus parameter is modified by the validators.

Before the XHedge upgrade, to increase (decrease) it by a predefined percentage, a qualified EOA call the `increaseMinGasPrice` (`decreaseMinGasPrice`) function, respectively. A qualified EOA is a validator or a validator's `rewardTo` account. This method may cause chaos of meaningless rising and falling.

After the XHedge upgrade, there is [a more sophisticated method](/smartbch/developers-guide/min-gasprice-decision) for the validators to vote for a final decision on the minimum gas price.

### Distribute Rewards

For each executed block, the gathered gas fee is distributed to the validators who proposed or voted for it.

The proposer can get two kinds of rewards:

1. The reward for being a proposer, i.e., not missing its duty, which is 15% of all the gas fee.
2. The reward for collecting signatures for the last block, which is at most 15% of all the gas fee. This reward is in direct proportion to the voting power the proposer collects. When all the voting power is collected, it can enjoy 15%

After the proposer gets its rewards, the remained gas fee is distributed to the voters. The proposer is also a voter by nature, so it can also enjoy some reward as a voter. A voter's reward is in direct proportion to its voting power.

The distributed rewards are not immediately given to validators' `rewardTo` accounts. Instead, they are pending till the next epoch's end. That is, the rewards gained in epoch N will be given to a validator's `rewardTo` account at the end of epoch N+1.

A validator's life cycle ends when its voting power is zero and all the pending rewards are given to its `rewardTo` account.

### Slashing

When a validator's misbehavior is discovered, its pending rewards will be all confiscated and a fixed amount of collateral will be slashed.

Currently, only double-signing is considered as a misbehavior.


# XHedge Smart Contract

In the white paper of smartBCH, we wrote: "During an epoch, BCH owners prove their ownerships of time-locked UTXOs and use the values of these UTXO to vote for a validator; whereas mining pools use coinbase transactions to vote...At the first phase after Smart Bitcoin Cash's launch, only hash power is used for electing validators. Locking BCH at mainnet for staking will be implemented later and take effect in a future hard fork."

These words describe a popular PoS scheme requiring the holders to "lock" their coins for some time. It has an obvious disadvantage: when the holders vote for a validator, they will lose their opportunities of depositing the coins in DeFi and earning some benefits.

After the launching of smartBCH, we the developers have been thinking about how to implement staking without this disadvantage. And the solution is surprisingly simple: the voters must be the guys who would like to "long Bitcoin Cash and short the world".

The PoS scheme of smartBCH begins with a smart contract named XHedge which extends the function of AnyHedge (a famous Bitcoin Cash futures contract). Then it combines XHedge and the concept of coin-day to enable voting.

#### The simple way

If you are impatient to learn the details of the XHedge contract and just want to use the basic PoS function, here is a short introduction.

By staking BCH into the XHedge contract, you get a pair of NFTs: the LeverNFT and the HedgeNFT. You can set a validator's pubkey as the LeverNFT's "supporting validator". As time goes by, the coindays (staking amount ✖ time duration) accumulate. Anyone can make a LeverNFT t vote for its supporting validator using the accumulated coindays. And the accumulated coindays will be cleared to zero after voting.

You can change the LeverNFT's supporting validator anytime. And when you want to stop staking, you just burn the pair of LeverNFT and HedgeNFT to get back the staked BCH.

To prevent SPAM, when a new validator is voted for the first time, at least 500 coindays are needed.

#### A thorough description of XHedge

Just like AnyHedge, XHedge needs one or more oracles to provide the price of BCH (relative to USD).

Suppose now BCH's price is `P0` and Bob wants to use XHedge to divide some BCH into a pair of LeverNFT/HedgeNFT. He must provide the following arguments:

1. The initial collateral rate: `CR0`
2. The minimum collateral rate: `CRmin`
3. The value contained in the HedgeNFT (measured in USD): `Vh`
4. Penalty on closeout: `Pc`
5. Mature time: `MT`
6. A validator Bob would like to support
7. The price oracle that this pair of NFTs will trust

And then XHedge will deduct some BCH from Bob's account and lock them. The locked Amount is `A=(1+CR0)*Vh/P0`. After that Bob gets a LeverNFT and a HedgeNFT, which can be transferred to other persons. In some scenarios, these NFT can be both burnt and the BCH locked because of them will be liquidated:

1. Before the mature time, if the price drops to `P1` and the locked BCH cannot meet the minimum collateral rate (`A < (1+CRmin)*Vh/P1`), then the owner of HedgeNFT can initiate liquidation. The owner of HedgeNFT can get `min(A, (1+Pc)*Vh/P1)` and the owner of LeverNFT, `max(0, A-(1+Pc)*Vh/P1)`.
2. After the mature time `MT`, any owner of these two NFTs can initiate liquidation. At the liquidation moment, if BCH's price is `P2`, then the owner of HedgeNFT can get `min(A, Vh/P2)` and the owner of LeverNFT, `max(0, A-Vh/P2)`. The owner of HedgeNFT secures the value of her asset, while the owner of LeverNFT enlarges her risk and benefit.
3. At any time, if both LeverNFT and HedgeNFT belong to the same account, then this account can get all the locked BCH by burning both NTF tokens.

The owner of LeverNFT can increase or decrease the locked BCH amount `A`:

1. At any time, she can deposit more BCH to enlarge A: add margin to avoid closeout
2. When the current price `P` is large enough for `P>P0*CR0`, she can withdraw some BCH to shrink A (reduce the margin), as long as A is no less than `(1+CR0)*Vh/P` after withdrawing. And, from the coins withdrawn by her, 0.5% is deducted and paid to the owner of HedgeNFT as a compensation fee.

Now we'd like to add some functions to XHedge to enable voting.

XHedge will record how long the coins have been locked because of a pair of NFTs, which is used to calculate the accumulated coin-day. One coin-day means one BCH is locked for 24 hours. Anyone can send transactions to:

1. Use this pair of NFT to vote for the supported validator, and the voting power equals the accumulated coindays. To prevent SPAM, when a new validator is voted for the first time, at least 500 coindays are needed.
2. And, at the same time, reset the accumulated coindays to zero.

Since anyone can send transactions to reset the accumulated coindays, it is very hard for the LeverNFT's owner to accumulate a lot of coindays. It will be very common for a validator to scan HedgeNFTs that are supporting her and turn the accumulated coin-days into votes before the next epoch.

XHedge will be implemented in EVM bytecode (compiled from solidity), just like any other smart contract. Inside its storage, the accumulated coindays voted for each validator are recorded. When switching to another epoch, the staking logic of smartBCH will scan these records for voting information and then clears these records.

Who has the right to change the supported validator? The owner of the LeverNFT. Because only she is a stakeholder of BCH, while the owner of HedgeNFT is actually holding USD.

After splitting his BCH into LeverNFT and HedgeNFT, Bob can deposit the NFTs into DeFi for earning. At the same time, the LeverNFT is continuously voting for the validator he supports, as long as the DeFi application which manages the LeverNFT does not change the supported validator.

To sum up, smartBCH's PoS scheme has the following advantages:

1. Having voters for the validators be long-positions, it creates an even stronger alignment of incentives compared to "just" locking coins
2. The BCH involved in DeFi applications can also be used for voting
3. Allows the holders to borrow stable tokens by taking BCH as collateral
4. The LeverNFT/HedgeNFT are always created and burnt in pairs, you do not have to worry about liquidity at closeout moments
5. Decentralized stable coins and other DeFi applications can be built upon HedgeNFT and/or LeverNFT.

#### How XHedge interacts with underlying golang logic

XHedge is just a plain smart contract implemented in EVM bytecode. It can affect the validator election because smartbchd's underlying golang logic reads and writes its storage.

When switching epochs, the voting information of the XHedge contract is read out and used to elect new validators, together with the PoW information in 50-50 weights. After that, the voting information is cleared from the XHedge contract's storage.

#### The price oracle for XHedge

There have been several DEX markets on smartBCH and the total BCH reserve in these pools is more than 130,000 now. This liquidity is enough to make a trustable price oracle.

All these DEX markets use UniswapV2-style pools, which means we can get their cumulative `price ✖ duration` products through the `price0CumulativeLast` and `price1CumulativeLast` functions, and the pool's token reserve through the `getReserves` function.

Based on these data, we develop [xhedge-price-oracle](https://github.com/smartbch/xhedge-price-oracle). It traces the DEX prices in half-an-hour time slots. During each time slot, the `price ✖ duration` product is sampled once at each pool, while the token reserve can be sampled multiple times and the smallest value will be kept at last.

It outputs the weight-averaged and time-averaged price from the data collected in the past 12 hours.

At each pool, a time-average price is calculated from the data collected in the last 12 hours. From these prices from pools, the oracle contract outputs a weight-averaged price. A pool's weight equals the minimum BCH reserve it had during the past 24 time slots.

Any EOA (externally owned account) can trigger xhedge-price-oracle to sample DEX pools, but smart contracts are forbidden to do so, because they can use flashloans to manipulate the sampled data.


# Decision of the minimum gas price

The chain-wide minimum gas price is a consensus parameter, which is the lower bound of the minimum gas prices set by different validators. This consensus parameter is modified by the validators.

After the XHedge upgrade, validators (or their corresponding `rewardTo` account) can send transactions to the staking contract (address: 0x2710) to anticipant the decision of minimum gas price.

The staking contract is a system contract implemented natively using golang, instead of solidity. However, we provide a pseudo-code at the end of this document to show how the logic of gas price decisions, hoping it can help your understanding.

## The logic of gas price decisions

There are two hard-coded constants: the upper bound and lower bound of the minimum gas price. The decided minimum gas price cannot exceed these bounds.

The minimum gas price is decided in a voting process:

1. A validator starts a voting process by calling `proposal`. This function's argument is the target minimum gas price this validator votes for.
2. The other validators call `vote` to specify the target minimum gas price of each one.
3. The voting process will last for 24 hours. When it ends, anyone can call `executeProposal` to make the decision effective.

The decided minimum gas price is the middle of the arithmetic mean value and the geometric mean value of all the voted targets.

## Psuedo code

```solidity
contract MinGasPriceVote {
	uint constant MinGasPriceDeltaRate = 5;
	uint constant MinGasPriceUpperBound = 500000000000; //500gwei
	uint constant MinGasPriceLowerBound = 10000000;   //0.01gwei
	uint constant DefaultProposalDuration = 60 * 60 * 24;    //24hour

	uint minGasPrice public;
	uint endVotingTime public;
	address[] voters public;
	mapping(address => uint) voteMap public;

	function proposal(uint target) external {
		require(isValidator(msg.sender), "not-a-validator");
		uint64 votingPower = getVotingPower(msg.sender);
		require(votingPower != 0, "inactive-validator");
		require(endVotingTime == 0, "is-still-voting");
		checkTarget(minGasPrice, target);
		endVotingTime = block.timestamp + DefaultProposalDuration;
		voteMap[msg.sender] = (target<<64) + uint(votingPower);
		addVoter(msg.sender);
	}

	function checkTarget(uint lastMinGasPrice, uint target) private {
		require(MinGasPriceLowerBound < target, "target-too-small");
		require(target < MinGasPriceUpperBound, "target-too-large");
		if(lastMinGasPrice != 0) {
			require(lastMinGasPrice/MinGasPriceDeltaRate <= target &&
				target <= lastMinGasPrice*MinGasPriceDeltaRate, "target-outof-range");
		}
	}

	function addVoter(address voter) private {
		for(uint i=0; i<voters.length; i++) {
			if(voters[i] == voter) return;
		}
		voters.push(voter);
	}

	function vote(uint target) external {
		require(isValidator(msg.sender), "not-a-validator");
		uint64 votingPower = getVotingPower(msg.sender);
		require(votingPower != 0, "inactive-validator");
		require(endVotingTime != 0, "not-in-voting");
		require(block.timestamp < endVotingTime, "voting-finished");
		if(target == 0) {
			target = minGasPrice;
		} else {
			checkTarget(minGasPrice, target);
		}
		voteMap[msg.sender] = (target<<64) + uint(votingPower);
		addVoter(msg.sender);
	}

	function executeProposal() external {
		require(endVotingTime != 0, "not-in-voting");
		require(endVotingTime < block.timestamp, "voting-not-finished");
		minGasPrice = calculateMinGasPrice();
		endVotingTime = 0;
		uint index = voters.length-1;
		do {
			address voter = voters[index];
			delete voteMap[voter];
			voters.pop();
			index--;
		} while(index!=0);
	}

	function calculateMinGasPrice() private returns (uint) {
		uint sumPower = 0;
		uint sumTargets = 0;
		uint[] memory targets = new uint[](voters.length);
		for(uint i=0; i<voters.length; i++) {
			address voter = voters[i];
			uint vote = voteMap[voter];
			(uint target, uint votingPower) = (uint(vote>>64), uint(uint64(vote)));
			sumPower += votingPower;
			sumTargets += target*votingPower;
			targets[i] = target;
		}
		uint t1 = calculateMeidan(targets);
		uint t2 = sumTargets / sumPower;
		return (t1+t2)/2;
	}

	function calculateMeidan(uint[] memory targets) private pure returns (uint) {
		uint index = targets.length/2; 4/2=2
		if(index*2 == targets.length) {
			returns (targets[index-1] + targets[index]) / 2
		}
		return targets[index];
	}

	function sort(uint[] memory arr) private pure {
	    if (arr.length > 0)
	        quickSort(arr, 0, arr.length - 1);
	}
	
	function quickSort(uint[] memory arr, uint left, uint right) private pure {
	    if (left >= right)
	        return;
	    uint p = arr[(left + right) / 2];   // p = the pivot element
	    uint i = left;
	    uint j = right;
	    while (i < j) {
	        while (arr[i] < p) ++i;
	        while (arr[j] > p) --j;         // arr[j] > p means p still to the left, so j > 0
	        if (arr[i] > arr[j])
	            (arr[i], arr[j]) = (arr[j], arr[i]);
	        else
	            ++i;
	    }
	
	    // Note --j was only done when a[j] > p.  So we know: a[j] == p, a[<j] <= p, a[>j] > p
	    if (j > left)
	        quickSort(arr, left, j - 1);    // j > left, so j > 0
	    quickSort(arr, j + 1, right);
	}
}
```


# Sha-Gate Specification

SHA-Gate (Smart-Holder-Authorized-Gate) is a new bridging scheme that help users transfer their BCH between the Bitcoin Cash main chain and the smartBCH side chain. It also helps synchronizing the "to-be-burnt" BCH held in the side chain's blackhole address to the burning address on the main chain.

## Overview

SHA-Gate works by creating, coverting and redeeming cc-UTXOs (chain-crossing UTXOs). A cc-UTXO is a cashscript covenant which can be spent by operators and monitors, which are elected periodically.

You can transfer BCH from the main chain to smartBCH side chain by creating a cc-UTXO, and transfer BCH from the smartBCH side chain to the main chain by redeeming a cc-UTXO. When the operators and monitors change after election, the existing cc-UTXOs must be converted to new ones that are controlled by the new operators and monitors.

After its creation, a cc-UTXO must be converted or redeemed as a whole. It cannot be split into smaller ones.

## Terminology

**The operators**. Each operator keeps a secp256k1 private key. By using their keys to sign transactions, they can spend cc-UTXOs together, converting or redeeming them.

**The monitors**. The monitors' tasks include: 1) When they find risks or possible bugs, they can stop the operators and stop the SHA-Gate logic in smartbchd; 2) Monitors can send transactions to synchronize the smartbchd nodes in processing the new BCH blocks which possibly contain chain-crossing tranfer transactions; 3) when the majority of the operators are unavailable, monitors can use their private keys to move the cc-UTXOs to a new operator set. A monitor controls a side chain account for task 1) and 2), and a main chain account for task 3).

**The collectors**. They collect signatures from the operators, assemble them into transactions, and broadcast the transactions on the BCH main chain. Collectors are permissionless and anyone can run. Usually volunteers run the collectors.

**The covenants**. A covenant is a script segment which controls who and how can spend a UTXO. The hash160 of the covenant is the UTXO's P2SH address, also know as the covenant's address. Usually this segment contains two parts: constructor arguments (some PUSH opcodes) and bytecodes compiled from the covenant's functions. The cc-UTXO's covenant constructor arguments are used to encode information about monitors and operators. So when monitors and operators change, the cc-UTXO's covenant address changes too. The current (last) covenant address reflects the latest (last) election's result, respectively.

**The chain-crossing contract**. A smart contract with address 0x2714, which is implemented using golang in smartbchd. It maintains the cc-UTXO set and help users redeem them.

**The blackhole account**. A special account with address 0x0000000000000000000000626c61636b686f6c65 (ascii of "blackhole"). All the burnt gas fee on the side chain will be sent to this account. On the main chain, the same amount of BCH equaling to this blackhole's balance will be: 1) transfered to the burning address "1SmartBCHBurnAddressxxxxxxy31qJGb" or 2) paid to the miners for converting cc-UTXOs to a new covenant address.

**The epoch**. One epoch is 2016 Bitcoin Cash blocks. Sha-gate uses it as a time unit.

## The details of cc-UTXO

Chain-crossing UTXOs use a special kind of covenants. The internal logic is: 1) when 7-of-10 operators agree, a UTXO can be transferred to a P2PKH address, or a new covenant address, or the burning address; 2) if a cc-UTXO has not been moved for a long time, then the monitors can transfer it to a new covenant address. The smartbchd nodes will analyze the transactions on BCH main chain to trace the cc-UTXOs' creation, redemption (transferred to a P2PKH address), and coversion (to a new covenant address).

#### Create a cc-UTXO

The value of cc-UTXOs has a upper bound Smax and a lower bound Smin. If the amount transferred to smartBCH is larger than Smax, the receiver on smartBCH will not get this amount. Instead, this cc-UTXO will be marked as "LostAndFound". A LostAndFound cc-UTXO can only be redeemed by this receiver by calling the chain-crossing contract with zero BCH. The LostAndFound machanism is to warn the receiver: please never do this again.

Now let's consider the situation where the amount is smaller that Smin:

1. If the amount is also smaller than `balance_of_blackhole_account - balance_of_mainchain_burning_address - 10`, then the receiver can get this amount on smartBCH and this cc-UTXO will be sent to the burning address "1SmartBCHBurnAddressxxxxxxy31qJGb" by the operators; we call such scenarios as "transfering small amounts through burning".
2. or else the receiver gets nothing and this cc-UTXO will be marked as "LostAndFound" (just like the situation where the amout is larger than Smax).

When Alice transfer some BCH from main chain to side chain, she puts the coins in a cc-UTXO, and uses an OP\_RETURN output to attach a sidechain address. The hex address following OP\_RETURN can be 40 bytes long (without the 0x prefix) or 42 bytes long (with the 0x prefix). If there are multiple OP\_RETURN outputs in the transaction, only the first one containing a hex address will be used.

If no sidechain address is attached, smartbchd examines the inputs one by one. When it finds the one which spends a P2PKH output, it uses the pubkey in its scriptSig to derive a sidechain address. If no P2PKH input can be found, then this tranfer fails and the coins are lost forever.

Alice should use the current covenant address as the cc-UTXO's P2SH address. If she incorrectly uses the last covenant address, the cc-UTXO will be marked as "LostAndFound".

Monitors can mark some main chain blocks as end-of-rescan blocks. The election, i.e., counting of votes for operators/monitors, happens at some of these end-of-rescan blocks. Conceptually, the changing of the covenant address happens at an end-of-rescan block. After this block, Alice should use the new covenant address, because the quorem of operators/monitors changes.

When transferring coins from the main chain to the sidechain, the sender will pay for the miner fee. The BCH amount Alice gets on the side chain equals the value of the created cc-UTXO.

#### Redeem a cc-UTXO

When transferring coins from the side chain to the main chain, Alice must redeem one or more cc-UTXOs in whole. Operators never divide or merge cc-UTXOs. Alice specifies her P2PKH address on the side chain and pays enough coins to the chain-crossing contract to redeem a cc-UTXO. The chain-crossing contract will generate an unsigned transaction which needs to be signed by the operators. This transaction will be published through a RPC endpoint, such that the monitors can see it and check it. After a publicity period, the operators can get this transaction through another RPC endpoint and sign it, such that collectors can fetch the operators' signatures and assemble a transaction. If the monitors want to stop operators, they must stop the SHA-Gate logic through the chain-crossing contract during the publicity period, thus the operators will not get this transaction to sign.

When transferring coins from the sidechain to the main chain, the miner fee will be deducted from the cc-UTXO. The redeeming transaction has exactly one input and one output. The BCH amount Alice gets on the main chain is less than the amount she paid on the side chain, and the difference is the miner fee.

#### Covert a cc-UTXO

When the operators/monitors set is changed after an election, the old operators must covert the cc-UTXOs to a new covenant address which can be controlled by the new operators/monitors set. Even if the operator set keeps unchanged for a long time, operators will also move and recreate the cc-UTXO every 12 epochs. This will prevent the monitors from moving the cc-UTXOs.

Please note monitors can only move the cc-UTXOs when they are old enough, which means most of the operators have been unavailable for 16 epochs. When we must rely on the monitors to move cc-UTXOs, smartbchd must be hard forked to handle such a restoration after a disaster.

When coverting cc-UTXOs, the miner fees are paid using the balance of the blackhole account. That means, some of the BCH burnt on smartBCH will not be synchronized to the main chain burning address. Instead, they are used to pay the miner fee of coverting cc-UTXOs. Anyone can sent BCH to the blackhole account as a donation for miner fees.

Before transferring the cc-UTXOs to a different operator set, a publicity period is also needed, during which the monitors check the transactions and can stop the SHA-Gate logic if there is a bug or risk.

You cannot redeem a cc-UTXO controlled by the old covenant address. You must wait until it is coverted to the new covenant address.

After a end-of-rescan block which changes the quorem of operators/monitors, if Alice accidently transfer coins to the old covenant address, then her cc-UTXO will be marked as LostAndFound. In the UI of an App or a web page which helps chain-crossing, Alice will be warned that the couting of votes is going to happen and she'd better delay the transfer.

## The details of the chain-crossing contract

The chain-crossing contract has the following external functions:

```solidity
    function startRescan(uint256 endOfRescanBlockHeight) external;
    function handleUTXOs() external;
    function pause() external;
    function resume() external;
    function redeem(uint256 txid, uint256 index, address targetAddress) external payable;
```

**startRescan**. This function requests all the smartbchd nodes to rescan the latest main chain blocks.

This function can only be called by a monitor. Why? The block interval of Bitcoin Cash is ten minutes averagely, but it varies a lot from block to block. A block may be orphaned and it only gets finalized after ten confirmations. Considering these issues, it isn't always easy to make all the smartbchd nodes come to consensus in synchronization about which BCH block is the latest finalized one. An evil attacker may secretly mine a fork and broadcast it at a subtle timing to make the smartbchd nodes see different forks.

So we rely on the monitors to specify the latest finalized BCH block's height, at a proper moment. All the smartbchd nodes will collect cross-chain transactions from the last processed height to `mainFinalizedBlockHeight`, and then these transactions are cached.

If there is an election to be finished, the couting of votes is carried out at the beginning of startRescan. But the election result does not have effect to the scanned cross-chain transactions, because they happend before this end-of-rescan block. Instead it will have effect to the future cross-chain transactions.

**handleUTXOs**. Twenty minutes after the monitor specify the latest finalized height, anyone can call this function to trigger the smartbchd nodes to process the cached cross-chain transactions. New cc-UTXOs are recorded in smartbchd nodes' internal storage. The cc-UTXOs which were marked as "to be deleted" will be deleted when smartbchd finds them were spent on the main chain.

The transactions for coverting cc-UTXOs are also considered as special chain-crossing transactions and will be processed by handleUTXOs.

**pause**. A monitor can call this function to stop smartbch'd chain-crossing logic and to prevent the operators from signing transactions. Monitors will check the events and status of smartbchd nodes to ensure things are going fine without bugs or risks.

**resume**. A monitor can call this funtion to cancel its pause command. Each monitor places and cancels its pause command independently. If there is at least one monitor places a pause command, then sha-gate is paused.

**redeem**. This is a payable function. When call it with zero value, you can redeem a cc-UTXO which is marked as LostAndFound, if you are its receiver. When call it with a non-zero value that equals the amount of the specified normal cc-UTXO, you can redeem this cc-UTXO. The `txid` and `index` arguments specify the cc-UTXO you want to redeem. A cc-UTXO can be redeemed only if it has been recognized in handleUTXO for more than 24 hours.

The operators will send this cc-UTXO to a main chain address specified by `targetAddress`, after you successfully redeem it on the side chain.

When a cc-UTXO is redeemed by Alice, its record is not immediately deleted from smartbchd nodes' storage, instead, it is just marked as "to be deleted". Some time after that, when this cc-UTXO is transferred to `targetAddress`, its record will be deteted on smartBCH.

The chain-crossing contract has the following events:

```solidity
    event NewRedeemable(uint256 indexed txid, uint32 indexed vout, address indexed covenantAddr);
    event NewLostAndFound(uint256 indexed txid, uint32 indexed vout, address indexed covenantAddr);
    event Redeem(uint256 indexed txid, uint32 indexed vout, address indexed covenantAddr, uint8 sourceType);
    event ChangeAddr(address indexed oldCovenantAddr, address indexed newCovenantAddr);
    event Convert(uint256 indexed prevTxid, uint32 indexed prevVout, address indexed oldCovenantAddr, uint256 txid, uint32 vout, address newCovenantAddr);
    event Deleted(uint256 indexed txid, uint32 indexed vout, address indexed covenantAddr, uint8 sourceType);
```

**NewRedeemable**. During the execution of handleUTXOs, this event denotes that a newly-created normal cc-UTXO is discovered.

**NewLostAndFound**. During the execution of handleUTXOs, this event is emitted when:

1. The value of cc-UTXO is too large.
2. The value of cc-UTXO is too small and it does not meet the requirement of "transfering small amounts through burning".
3. The P2SH address is the last covenant address, instead of the current covenant address.

**Redeem**. This event can be emitted by the handleUTXO function or the redeem function. During the execution of handleUTXOs, this event is emitted when it is "transfering small amounts through burning" (sourceType=9). During the exectuion of redeem, this event denotes a normal cc-UTXO is redeemed (sourceType=0) or a LostAndFound cc-UTXO is redeemed (sourceType=1).

**ChangeAddr**. During the execution of startRescan, if votes are counted for an election, this event will be emitted to reflect the changing of cc-UTXO's P2SH address.

**Convert**. This event can be emitted by the handleUTXO function, to denote a cc-UTXO is coverted to the new covenant address.

**Deleted**. During the execution of startRescan, this event is emited when a cc-UTXO is transfered to the `targetAddress`, or to the burning address. If this cc-UTXO was once a LostAndFound cc-UTXO, sourceType is 1; if it was once a normal cc-UTXO, or was "transfering small amounts through burning", sourceType is 2.

These events help the monitors to know what happen inside smartbchd.

## Security Considerations

**The operators**. An operator's key is generated inside an enclave, bonded to the binary code of the enclave, and can only be used by this enclave: it can not be used by an enclave with a different binary or on a different CPU. We assume an operator is well-intentioned because it always does exactly what is specified in the source code. The bad things that can happen to an operator are: A) bugs (its own bugs or smartbchd's bugs); B) it is fooled by the smartbchd nodes it's connecting to; C) it is unavailable (power-off or disconnected from the internet). Because of the bad things B and C, we need multiple operators for robustness. To minimize the possibility that operators have bugs, their source code must be very simple: they just get signing tasks from smartbchd nodes and sign them blindly. We hope their source code can keep unchanged for a long time (even forever).

The operators don't need to connect to BCH full nodes. They just connect to the smartbchd nodes. A smart contract will publish the domains and TLS certification of the trustworthy nodes. We suggest that the trustworthy nodes run in enclaves (most likely SEV-SNP enclaves). Any engineer can independly verify that they are really run in enclaves and the executable binary has correct version. Monitors will also verify this.

This smart contract for publishing nodes is maintained by a group of trustworhty engineering experts, who endorse the nodes using their knowledge.

**The monitors**. A monitor controls a side chain account to call the chain-crossing contract, and a main chain account to move the cc-UTXOs. The side chain account's private key must be stored in a running server. We suggest to use enclaves to protect such private keys. But these keys are not bonded to the binary code of the enclave. The main chain account's private key must be stored in off-line cold wallets that are kept by some trustworthy persons.

The monitor's source code is very easy to be updated, much easier than the operator or the smartbchd full-node. So we can apply flexible strategies using the monitors. For example, we can require that the total amount of redeemed cc-UTXOs in the past 24 hours must be less than a given threshold. If the amount exceeds, the monitors will pause sha-gate for a while.

## Election of operators and monitors

Operators are elected with staked coins on the smartBCH side chain, while monitors are elected with hashing power on the main chain. Only a part of them are re-elected at a time. It is planned that there are ten operators and three of them are re-elected in each round, while there are three monitors and one of them are re-elected in each round.

BCH holders must stake their coins to vote for operators. And each monitor or operator must stake for itself with enough BCH, i.e., it must lock their own coins on the side chain, which means if SHA-Gate malfunctions, it will also suffer. The staked coins cannot be withdrawn (unstaked) until the operator or monitor is off duty.

Anyone can apply to be an operator or a monitor after self-staking enough BCH. A monitor also need nominations of half of the operators to be a candidator, while an operator becomes a candidator immediately after self-staking, without any nomination.

## Election of smartBCH nodes for operators

Operators must connect to several trustable smartbchd nodes for querying the RPC endpoints. These smartbchd nodes are elected by node proposers. When more than 2/3 of the node proposers agree, a new node can be added, or, an existing node can be obsoleted. Any monitor can obsolete a node immediately without voting.

The node proposers are decided by the operators. When the operator set is changed, the changed operator set is exactly the set of node proposers. And the proposers can vote to add new proposers or remove exsting ones.

An operator must connect to all the elected nodes. Becides these nodes, the operator's administrator can configure it to connect to one or more private smartbchd nodes which may not provide public RPC service. The operator only sign transactions when all the connected nodes return the same UTXO set.

## Appendix: RPC endpoints for chain-crossing

**sbch\_getCcCovenantInfo**: returns information related to generating chain-crossing convenants P2SH address. The result is a json string:

1. operators: the current quorem of operators
2. monitors: the current quorem of monitors
3. oldOperators: the old quorem of operators before the lasting changing of operators or monitors
4. oldMonitors: the old quorem of monitors before the lasting changing of operators or monitors
5. lastCovenantAddress: the last P2SH address calculated based on last quorems (old\_operators and old\_monitors)
6. currCovenantAddress: the current P2SH address calculated current quorems
7. lastRescannedHeight: the last end-of-rescan block's height
8. rescannedHeight: the current end-of-rescan height proposed by the monitor
9. rescannTime: the current end-of-rescan time proposed by the monitor
10. signature: the signature of the above fields

In the json string, an operator is an object with following attributes:

1. address: the operator's EVM address on smartBCH
2. pubkey: the operator's public key used in the covenants
3. rpcUrl: the operator's public rpc
4. intro: an introduction

And a monitor is an object with following attributes:

1. address: the monitor's EVM address on smartBCH
2. pubkey: the monitor's public key used in the covenants
3. rpcUrl: the operator's public rpc
4. intro: an introduction

**sbch\_getRedeemingUtxosForMonitors**: returns cc-UTXOs which needs redeeming. The results are checked by the monitors.

**sbch\_getRedeemingUtxosForOperators**: returns cc-UTXOs which needs redeeming. The results are checked by the operators.

**sbch\_getToBeConvertedUTXOsForMonitors**: returns cc-UTXOs which needs to be coverted to new operator/monitor quorem. The results are checked by the monitors.

**sbch\_getToBeConvertedUTXOsForOperators**: returns cc-UTXOs which needs to be coverted to new operator/monitor quorem. The results are checked by the monitors.

**sbch\_getRedeemableUTXOs**: return the cc-UTXOs which can be redeemed by smartBCH accounts.

The cc-UTXOs returned by above RPC endpoints are json objects with following attributes:

1. infos: a list of cc-UTXOs. Each entry contains the following fields:
   1. ownerOfLost: if the cc-UTXO is marked as "LostAndFound", this is its owner
   2. covenantAddr: the P2SH address calculated for this covenant
   3. isRedeemed: some account has already redeemed this cc-UTXO
   4. redeemTarget: the main chain address where this cc-UTXO will go to
   5. expectedSignTime: when will the operators sign the txSigHash with its private key
   6. txid: the cc-UTXO's txid on main chain
   7. index: the cc-UTXO's index of vout on main chain
   8. amount: the amount (in satoshi) of this cc-UTXO
   9. txSigHash: To convert or redeem this cc-UTXO, the operator must sign this hash with its private key
2. signature: the signature of the infos

The returned results of these RPC endpoints all constain a signature to endorse the other fields. The private key for generating signatures is hold only in smartbchd's memory, instead of configuration files. With the signatures, operators can make sure that the returned results are not manipulated. They provide another level of safeguard besides TLS.

## Appendix: Chain-crossing Transactions on the Main Chain

The transactions on Bitcoin Cash main chain are scanned by smartbchd one by one to pick up the ones that are related to chain-crossing. Three types of chain-crossing transactions are defined, and smartbchd will take different actions to them.

A transaction is categoried as **Redeemable** type if: 1) it has at least one P2SH output; 2) this P2SH output's address is the current covenant address or the last covenant address; 3) a receiver can be found in a OP\_RETURN output or a P2PKH input.

If there are multiple P2SH outputs with the current covenant address or the last covenant address, only the first one will be considered, and the coins in the other outputs will be ignored by smartbchd.

A transaction is categoried as **Convert** type if: 1) it has exactly one P2SH input and one P2SH output; 2) the output's P2SH address is the current covenant address; 3) the input is a cc-UTXO waiting for converting.

A transaction is categoried as **RedeemOrLostAndFound** type if: 1) it has exactly one P2SH input and one P2PKH output; 2) the P2SH input is a cc-UTXO waiting to be sent to the target of redeeming or the owner of lost.

This rescan process is triggered by monitors calling the `startRescan` function. This function will count the votes and decide the current covenant address, the last covenant address, and the cc-UTXO set waiting for converting. After this function, this rescan process will be run in the background to collect these three types of chain-crossing transactions and cache them in memory. The execution of `handleUTXO` will be blocked if this background rescan process has not finished.

## Appendix: The election of operators and monitors

The election of operators and monitors is done by both smart contracts and golang code of smartbchd. The latter counts the votes and the former finishes the other tasks.

To be a operator, you must finish the following steps:

1. Apply for the job as an operator. It requires you to stake some SBCH larger than a minimum amount.
2. Holders on the side chain stake SBCH to vote for you.
3. A the time of counting votes, you collect enough votes.

There are 10 operators in total. At most three of them are re-elected every four epochs. When couting votes, the top three new-elected operators (which are not in current quorem) and the current quorem are sorted together to find the top 10 operators with most votes.

To be a monitor, you must finish the following steps:

1. Apply for the job as a monitor. It requires you to stake some SBCH larger than a minimum amount.
2. At least five of the operators nominate you.
3. The POW miners vote for your with coinbase transactions.
4. A the time of counting votes, you collect enough PoW votes.

There are 3 operators in total. At most one of them are re-elected every 12 epochs. When couting votes, the top one new-elected monitor (which is not in current quorem) and the current quorem are sorted together to find the top 3 monitors with most PoW votes.

## Appendix: The service provided by operators

Operators run inside enclaves. They fetch to-be-signed UTXOs from the smartbchd nodes and sign them. Then they wait the collectors to query these signatures and assemble transactions.

For the operators, the highest risk is connecting to fake smartbchd nodes which returns incorrect information. To alleviate this risk, smartbchd nodes use a CC private key to sign the RPC results related to chain-crossing. From an operator's view, a smartbchd node is denoted by its RPC's URL and its CCPbkHash (the hash of the public key of the CC private key). The CC private keys are stored in off-line cold storages and are sent into smartbchd nodes through https when they starts. They are kept only in the smartbchd nodes' memory and if the node's process is re-started, they must be sent again.

So, if an attacker want to cheat an operator with a fake smartbchd node, he must first hack into the smartbchd node's memory and steal the private key and then use IP spoofing, IP hijack or DNS pollution to mislead the operator connects to a smartbchd node that uses this stolen key. Even such an attacker succeeds, the monitors can stop this operator. Monitors will watch the data that operators get from the smartbchd nodes, such as the UTXOs to be signed and the nodes to be connected. If these data are wrong, the operator will be stopped.

The smartbchd nodes may be controlled by corrupted and dishonest parts. So the operators do not trust any single one of them. Only when all these nodes returns the same result, the operators would trust it. If at least one of these nodes is honest, the operator cannot be fooled.

A smart contract on smartBCH elects the quorem of smartbchd nodes that will be connected by operators. If this quorem is changed, the operators will wait for a publicity period before switching. During this period the monitors can stop the operator.

The operator's enclave hold a private key for signing chain-crossing transactions. To protect this key, an operator has no public listening ports. Instead, it connects to a proxy server and let the proxy server talk to the public. This proxy server acts as a firewall.

An operator collects data through the smartbchd nodes' following RPC endpoints:

**sbch\_getRedeemingUtxosForMonitors**: Just to record these data for checking.

**sbch\_getRedeemingUtxosForOperators**: Use these data to sign hashes.

**sbch\_getToBeConvertedUTXOsForMonitors**: Just to record these data for checking.

**sbch\_getToBeConvertedUTXOsForOperators**: Use these data to sign hashes.

**eth\_call**: To collect the new elected smartbchd nodes

An operator provides service to the proxy through these RPC endpoints:

**/cert**: Returns the hex-encoded x509 certification.

**/cert-report**: Returns the attestation report endorsing the x509 certification.

**/pubkey**: Returns the hex-encoded public key of the private key used in signing transactions

**/pubkey-report**: Returns the attestation report endorsing the public key.

**/pubkey-jwt**: Returns an Azure-generated JWT to endorse the attestation report.

**/sig?hash=**: Given a to-be-signed hash, return the signature signed by the operator's private key.

**/nodes**: Return the current list of smartbchd nodes.

**/newNodes**: Return the next list of smartbchd nodes, which will be connected to after the publicity period.

Each entry in the nodes list has the following fields:

1. id: a unique number
2. pbkHash: the CCPbkHash
3. rpcUrl: the URL of this node's RPC
4. intro: a short introduction of this node

**/suspend?ts=\&sig=**: A monitor can call this RPC endpoint to stop the operator. Current time must has no larger than 1 minute different with `ts`. The `sig` is generated with the monitors private key which is used to sign the smartBCH transactions.

**/status**: Returns "suspended" if this operator is stopped by a monitor. Returns "ok" if not.


# Sha-Gate Risk Analysis

Risks can only be allieviated after we identify and analyze them. In the design of sha-gate, we have identified the following possible risks:

1. The code of smartbchd nodes has bugs related to sha-gate.
2. The operators collect to fake smartbchd nodes (intentionally or get hacked)
3. One or more operators get unavailable (intentionally or get hardware fault)
4. The private key of an operator is stolen out from the enclave (by the administrator or an attacker)
5. The monitor's EVM private key is stolen
6. The monitor's BCH private key is stolen
7. The monitor's EVM private key is lost
8. The monitor's BCH private key is lost
9. The node proposers elect a wrong node set

**Risk 1**: Some kinds of bugs can be discovered by the monitor, while some kinds can not. Anyway, the monitor needs to read the events generated by smartbchd nodes to find potential bugs. Currently, the monitor does not check the amount: for example, if a user can spend 0.1 SBCH to get 10 BCH on main chain, then such a bug cannot be discovered by the monitor currently.

No matter how we refine the code of monitor, there are always some kinds of bugs that cannot be discovered by it. So the monitors use another scheme for safeguard: if the total redeemed amount is larger than a given threshold in the last 24 hours, the monitors pause sha-gate. This scheme is used for damage control.

**Risk 2**: Let's consider the case that the nodes are hacked (DNS get polluted or something). Firstly we can use cloudflare or some other application firewalls to avoid such attacks. Secondly the RPC results related to chain-crossing are signed by a special private key, and the attacker can not do any harm without knowing this key. Thirdly the operators will do nothing if the nodes do not all return the same result, which means the attacker must hack all the nodes connected by the operator. Finally, monitors will also check that the operators are connecting to correct nodes and stop the operators if necessary.

Now let's consider the case that the administrator of an operator makes it connect to wrong nodes intentionally. The administrator inputs wrong bootstrap nodes to the operator enclave and he blocks out the monitors' stop commands.

To alleviate such a risk, we hard-coded two nodes in the operator's source code as bootstrap nodes. In case of these two nodes crashing, a special private key can authenticate other nodes to act as bootstrap nodes in a given period.

**Risk 3**: If the operator's SGX instance get power supply problem or networking problem, it will be unavailable for a while. If the server's CPU is damaged, the operator's private key will be lost forever. The 7-of-10 signature scheme can alleviate such a risk. If no more than three operators get such problems, we can always elect new operators to replace the fault ones.

**Risk 4**: Intel SGX2 enclaves have never leaked private key from inside, even when the administrators are evil. Even someday in the future a hacker can break into SGX2 enclaves, he must steal at least 7 private keys. This risk is low. But we still use proxies to protect the operators from directly facing internet traffic.

**Risk 5**: If a monitor's private key is stolen by an attacker, the attacker can pause the sha-gate and stop all the operators. But it cannot steal any coins as long as the operators do not collude. We can use a hard fork to exclude the evil monitors.

**Risk 6**: Only when at least seven operators get unavailable, the monitors' BCH private key are used to move the cc-UTXOs. In such cases, an attacker needs to steal two monitors' private keys to do evil. This risk is low.

**Risk 7**: If no more than two monitors lose their private keys, the other monitors can still do the duty of pausing sha-gate and stoping operators. We just need to elect new monitors.

**Risk 8**: Only when at least seven operators get unavailable, the monitors' BCH private key are used to move the cc-UTXOs. In such cases, the cc-UTXOs are stuck only when at least two monitors' private keys are lost. This risk is low.

**Risk 9**: The nodes proposers elects smartbchd nodes in a public process on the smartbch chain. And when the operators' enclaves get the new election result, they will delay some time before using it. So if the nodes proposers elects a set of evil smartbchd nodes, it is easy to be found by the community. The operators' administrators and monitors can stop the operators to deal with such cases.


# Sha-Gate's Covenant

The covenant used in Sha-Gate are implemented in CashScript to utilize self-introspection. It manages the cc-UTXOs which keep the coins transferred to the smartBCH sidechain.

The logic of this covenant is quite simple:

1. There are 10 operators and 3 monitors, whose hashes are encoded as the covenant's constructor parameters, i.e., part of the scriptPubkey.
2. If seven of the ten operators sign the transaction, this cc-UTXO can be spent in any way they want, as long as the transaction has only one input and one output. (`redeemOrConvert`)
3. If at least seven operators are unavailable for more than eight months, this cc-UTXO can be sent to a new operator set. (`convertByMonitors`)

It is very unlikely that we need to use `convertByMonitors`. So currently the smartbchd nodes do not recognoize such transactions. If such a accident really happens (at least seven operators are unavailable for more than eight months), the smartbchd nodes need to be hard-forked to recognize `convertByMonitors`.

The miner fee of `redeemOrConvert` is deducted from the input cc-UTXO and has an upper bound hardcoded in the covenant. And the miner fee of `convertByMonitors` is paid by some other input other than cc-UTXO.

In practice, the operators only sign two kinds of transactions using `redeemOrConvert`:

1. Send the cc-UTXO to a P2PKH address. For such cases, the covenant does not check anything.
2. Convert the cc-UTXO's constructor parameters, while keeping the covenant's logic unchanged. For such cases, the covenant checks the format of the resulted P2SH output.


# Introduction

Here are some documents describing how moeingads, moeingdb and moeingevm works.

Most of developers do not need care about these documents. But if you're going to use them in other projects, or want to review them to find bugs for smartBCH, you'll find them useful.


# MoeingADS's General Ideas

## 1.0 In the whole history of a blockchain, how can we prove which KV pairs were created/updated at which blocks?

When a Key-Value pair is created/updated at a block of Height, we create such an Entry:

```
Entry := (Height, Key, Value, SerialNum)
```

Through the history of the blockchain, we get a sequence of such entries. The SerialNum field shows an entry's postion in this sequence.

Then we build a balanced binary Merkle tree, with hash values of these entries as leaves. If the count of entries is not $2^N$, we just add null entries for padding, as is shown below (the null entries are grey).

![ADS\_1](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F842f173bc0c0fee28891f9acae00314b209addea.png?generation=1616929515744703\&alt=media)

Using the binary tree, we can prove the existence of an individual entry.

Of cause, in the implementation, we do not really add null entries for padding. Instead, we only need to add a null node at each level of the binary tree, as is shown below.

![ADS\_2](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F4b80eae6c0e667cf478e89cfabd287f6ba0a3961.png?generation=1616929521178907\&alt=media)

## 2.0 How to store such a Merkle tree

If we keep the whole Merkle tree in DRAM, then we can provide the proofs very fast. But unfortunately, it will cost a huge amount of DRAM so it is not feasible. A reasonable trade-off is: since the upper levels is more likely to get accessed than the lower levels, we can keep the upper levels in DRAM and the lower levels on hard disk.

In the current golang implementation of MoeingADS, we store the lowest 11 levels of nodes (which correspond to 2048 entries) on hard disk, as is shown below. Such a small sub-tree with 11 levels of nodes are named as a "twig". The youngest twig (in the read circle) has not got all its internal nodes fixed, since the 2048 entries are not decided yet. So we buffer this youngest twig in DRAM. All the other twigs are stored on hard disk.

![ADS\_3](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2Fca5497b8ced507d730d01551fc9413c28c5530f0.png?generation=1616929516391145\&alt=media)

## 3.0 How to prove a KV-pair is up-to-date? In other words, since some height H, an KV-pair is left untouched (not changed or deleted).

An ActiveBit is attached to each entry. If ActiveBit==1, then this KV-pair is up-to-date; if ActiveBit==0, then this KV-pair has been changed or deleted after the height recorded in the entry.

These ActiveBits need to be random-accessed, because an ActiveBits can be cleared to zero at any time. So we must keep all the ActiveBits in DRAM.

## 4.0 Should we build a dedicated Merkle tree for these ActiveBits?

Although we do want to provide Merkle proofs for some individual ActiveBit, a dedicated Merkle tree is not necessary. A more memory-efficient implementation is to integrate the ActiveBits into a twig. That is, a twig contains 2048 entries and the corresponded 2048 ActiveBits.

The small Merkle tree inside a twig now is made of two parts, as is shown below. The left part is a eleven-level tree with 2048 entries as its leaves. And the right part is a three-level tree with 8 leaves. Each leave contains 256 ActiveBits. And the Merkle root of the entire twig, i.e. TwigRoot as is shown below, is a hash value calculated from the roots of left part and right part.

![ADS\_4](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F0897cebe1b2db90b3bf84367e1f43ab1d5d69027.png?generation=1616929516336994\&alt=media)

## 5.0 How to prune the ActiveBits and entries?

We want to keep only the recent entries whose ActiveBits equal 1, and prune the old ones to save memory. But currently we can not make sure that the old enough entries are inactive (i.e. having their ActiveBits==0). Actually, even the oldest entries may be still active.

We have a counter measure: repeating redundant updates. We fetch the oldest entries and overwrite their value using exactly the same values. Thus new entries are created and the oldest entries are deactived.

The following picture shows a "redundant update" operation. Two oldest active entries (in the two red rectangles on the left side) are fetched out and two new entries are generated (in the red rectangle on the right side). Then the ActiveBits of the oldest entries are cleared to 0 and the ActiveBits and the newly-created entries are set to 1.

Using this method, we can ensure the old enough entries are deactived if their SerialNums are less than a particular value. The twigs whose entries' SerialNums are all less than this particular value are refered to as "inactive twigs", or else "active twigs". an inactive twig has all its ActiveBits==0. Please note an active twig can also has all its ActiveBits==0. We say a twig is "active" only because it MAY have ActiveBits==1.

![ADS\_5](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F606f04fb9018209b964ee5c7e1e84e212461906a.png?generation=1616929516074757\&alt=media)

## 6.0 How to provide non-existence proof? That is, we want to prove there are no other key(s) residing between key A and key B.

We need to extend entries with a NextKey field:

```
Entry := (Height, Key, NextKey, Value, SerialNum)
```

After Height, if some events happened between Key and NextKey (deletion, overwriting and insertion), then this entry is sure to be deactived and a new entry will be created.

## 7.0 How to proof a KV pair at any height? Even if at this height nothing happens on this KV pair.

Now, using the information in entries, we can prove at height H0 and height H, a KV-pair was created or updated. But we can not prove that nothing happened between H0 and H.

So we need to extend entries with a new field "LastHeight":

```
Entry := (Height, LastHeight, Key, NextKey, Value, SerialNum)
```

The information in an entry show:

1. At `Height`, the `Key`'s value is `Value`
2. There are no other keys between `Key` and `NextKey`
3. During `LastHeight` to `Height`, nothing happened between `Key` and `NextKey`

## 8.0 What are the possible statuses of twigs.

We can describe a twig's status using several terms.

![ADS\_6](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F769799bdfd2e14377f56c313c85710759bd0d78a.png?generation=1616929515772501\&alt=media)

First term: "Youngest". There is only one youngest twig (the green one in the above figure). A youngest twig has null entries. When all the 2048 entries are ready, it is no longer a youngest twig. Another twig with 2048 null entries will be created as the new youngest twig. Youngest twig is the only twig whose left eleven-level Merkle tree is stored in DRAM. For the other twigs, the left eleven-level Merkle trees are stored in hard disk.

Second term: "Active". An active twig contains at least one active entry, or there is at least one entry which is older than this twig. A youngest twig is certainly active. In the above figure, the blue and green triangles are active twigs. The active twigs use DRAM to store their right three-level Merkle trees whose leaves are the ActiveBits, such that these bits can be cleared at any time.

Third term: "Pruned". The inactive twigs can be kept in hard disk such that we can query about the historical KV-pairs of the blockchain. They can also be pruned if we not interested in these historical old KV-pairs. A non-pruned inactive twig is kept in hard disk, and a pruned inactive twig is deleted from the hard disk. In the above figure, the black triangles are non-pruned twigs and the orange triangles are pruned twigs.

A twig can be in one of four possible states:

1. Active and youngest
2. Active and non-youngest
3. Inactive and not-pruned
4. Inactive and pruned

## 9.0  How to query a KV pair fast?

We can build an index, which maps a (key, height) tuple to a 64-bit integer, which is the offset of the entry in file. If you want to know the latest value of the key, just set height to -1.

This index must support iterator, so hash tables do not work. We must use some tree structure, such as red-black tree (in DRAM), B/B+ tree (in DRAM or in disk), LSM tree (in disk). To balance speed and memory consumption, we use B-tree in DRAM to index the latest keys (height = -1) and RocksDB to index the historical keys. RocksDB supports pruning. It can prune the records whose height is old enough, during compaction.

## 10.0 How to prune the inactive twigs?

A block at height H can create one or more entries. The SerialNum of the first entry created by it is denoted as SerialNum(H). When we do not need the information about the blocks older than H, we can prune the twigs whose entries' SerialNum are smaller than SerialNum(H).

Filesystem does not support truncate a file from the beginning to a middle point. So we must use a series of small files to simulate one large file. Pruning the from the beginning is deleting the first several small files. We name such a virtual large file as "head-prunable" file.

The content of twigs are seperated and store in two head-prunable files: one for the leaves, i.ie. the entries, and the other for the left eleven-level Merkle tree. What about the right three-level Merkle tree? Well, for the inactive twigs, all the ActiveBits are zero, so the right three-level Merkle trees are the same.

The left eleven-level Merkle trees occupies constant bytes on disk. So it is easy to calculate any node's offset in file.


# MoeingADS's RabbitStore

EVM's semantics requires that an account's detail can be read/written by its 20-byte address, and a storage slot can be read/written using (20-byte address, 32-byte hash) tuple.

RabbitStore is a special KV store which uses short fixed-length keys for indexing. We can replace MultiStore with it to reduce DRAM usage.

## Rabbits hop to store and eat carrots

To explain how RabbitStore works, let's tell a story of rabbits first.

![Rabbit](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F09601b24a0d4df3ee04e932bddd0fefdf3e2388f.png?generation=1616929516046938\&alt=media)

There are 24 holes, each of which can hold a carrot. Rabbits come and put their carrots into holes according to given algorithm. Suppose now eight rabbits have come and put eight carrots in eight holes. Then the Alice rabbit is coming with her carrot which is named as "Alice's yummy carrot". Alice will do the following steps according to the algorithm:

1. She hashes the name "Alice's yummy carrot" once and gets a number 13 . She hops to the #13 hole and finds another carrot in it. So her carrot cannot be stored in this hole.
2. She hashes the name twice and get a number 22. She hops to the #22 hole and finds another carrot in it. So her carrot cannot be stored in this hole either.
3. She hashes the name for three times and get a number 21. She hops to the #21 hole and finds an empty hole. So she can store "Alice's yummy carrot" in it.
4. She places one stone at #13 hole and one stone at #14 hole, which mean she must pass by these holes to reach the correct hole storing her carrot.

Finally, the Bob rabbit is coming with his carrot which is name as "Bob's delicious carrot". He does similar steps as Alice. He hops to #22 hole first, and then hops to #11 hole, finding these holes are full. At last he find an empty #9 hole. He stores his carrot in #9 and place two holes at #22 hole and #11 hole.

Now, we can see #13 hole and #11 hole each have one pass-by stone, and #22 hole has two pass-by stones.

When a rabbit comes to eat her carrot, she must follow these steps:

1. Set n = 1
2. Hash her carrot's name for n times and gets a hole number, and then check the hole:
3. If her carrot is not there and there is no pass-by stone, her carrot can never be found (maybe eaten by someone else)
4. If her carrot is not there and there are one or more pass-by stone, set n = n + 1 and go to step 2.
5. If her carrot is there, she eats it and removes one pass-by stone from each hole she just passed by.

If there are empty holes, a rabbit can finally find one hole to store her carrot in finite steps. And if the carrot is still there, a rabbit can finally find it to eat in finite steps.

## Short fixed-length keys for indexing

The C++ version B-tree uses a special trick to reduce memory usage which only works when the key is 8 bytes long. But in practice, keys are usually quite long just like a carrot's lengthy name.

There are no more than 264 holes (because the key is 8 bytes long), and we must assign a hole number to some carrots with unique names. The number of carrots are far less than 264, but their names are much longer than 8. The rabbits' hopping algorithm can help us map lengthy names to 8-byte hole number.

In the underlying TrunkStore, the keys are 8-byte which are calculated . And the original variable length key-value pairs are packed together and used as the values stored in TrunkStore

By hashing the original keys, RabbitStore gets new 8-byte short keys. By packing the original variable-length key and value together, RabbitStore gets new values. These new keys and values are stored into the underlying TrunkStore. Thus the indextree only faces fixed 8-byte short keys, which allows C++ B-tree to do the trick.

The short 8-byte keys generated from adjacent original keys, will no longer be adjacent to each other any more. So RabbitStore cannot support iteration. Luckily, EVM only uses SSTORE and SLOAD to access the underlying persistent KV store and it does not need iteration at all.

## Performance Consideration

The possibility of rabbits' hopping path drops exponentially as its length grows. In practice, almost all of the hopping paths have only one hop. So the performance penalty of RabbitStore is negligible.


# MoeingADS's internal architecture

## Introduction to packages of moeingads

Here we introduce the packages and the data structures defined in the moeingads repo.

## moeingads

moeingads has three building blocks: index-tree, data-tree, and meta-db.

```
             +----------------+
             |                |
             |    moeingads   |
             |                |
             +----------------+
              /     /        \
             /     /          \ 
            /     /            \
           /   metadb           \
          /       |            datatree
      indextree   |            /      \
        /  \      |           /        \
       /    \     |   entry-file     twig-merkle-tree-file
      /      \    |           \         /
     /        \   |            \       /
    B-Tree   RocksDB            \     /
   (cpp&go)                      \   /
                           Head-Prunable File
```

### Head-Prunable File

See datatree/hpfile.go

Normal files can not be pruned(truncated) from the beginning to some middle point. HPFile use a sequence of small files to simulate one big file. Thus, pruning from the beginning is to delete the first several small files.

A HPFile can only be read and appended. Any byteslice which was written to it is taken as readonly can not be overwritten.

You can use `Append` to append a new byteslice into a HPFile, and `Append` will return the start position of this byteslice. Later you can pass this start position to `ReadAt` and read this byteslice out. The position passed to `ReadAt` must be the beginning of a byteslice, instead of its middle.

A HPFile can also be truncated: discarding the content from the given position to the end of the file. All the byteslices written to a HPFile during a block should be taken as one whole atomic operation: all of them exist or none of them exists. If a block is half-executed because of machine crash, that is, some of the byteslices are written and the others are not, then the written slices should be truncated away.

### Entry File

See datatree/entryfile.go

It uses HPFile to store entries, i.e., the leaves of the data tree. The entries are serialized into byteslices in such a format:

1. 8-byte MagicBytes, which is `[]byte("ILOVEYOU")`. We use MagicBytes to mark the beginning of an entry. In the entry file, you can find MagicBytes only at the beginning of every entries. If you read bytes out from a entry file and the beginning of these bytes is not "ILOVEYOU", then the read position must be wrong. This makes coding and debugging easier.
2. 4-byte Total Length (this length does not include padding, checksum and this field itself), in little endian. Using this information, you can fast skip an entry and access the next.
3. Int32 list of MagicBytes positions, which uses `-1` as the ending. Each Int32 takes 4 bytes, in little endian. Every position (except the last `-1`) gives a position where has 8 zero bytes and should be replace by MagicBytes. These posistions are relative to the end of 4-byte Total Length.
4. An entry's content, including: 4-byte key length, key's bytes, 4-byte value length, value's bytes, 4-byte next key length, next key's bytes, 8 bytes of height, 8 bytes of last height, 8 bytes of serial number. All these integers are little endian.
5. Int64 list of deactived serial numbers. , which uses `-1` as the ending. Each Int32 takes 4 bytes, in little endian. After the creation of last entry and before the creation of current entry, zero or more entries are deactived, and their serial numbers are recorded in this list.
6. 4-byte checksum, calculated using meow hash.
7. Several zero bytes for padding. The size of the serialized bytes must be integral multiple of 8.

By adding list of deactived serial numbers into entries, we make an entry file into a log file. If all the information in memory is lost, we can re-scan the entry file from beginning to end to rebuild all the state.

An entry's hash id is sha256 of its serialized bytes, which means the list of deactived serial numbers is also proven by the merkle tree. If you receive an entry file from an untrusted peer, you can verify its entries with the merkle tree.

### Twig Merkle Tree File

See datatree/twigmtfile.go

It uses HPFile to store small 2048-leave small Merkle tree in a twig. When someone queries for the proof of an entry, we can use this file to read the nodes in the small Merkle tree.

Each node occupies 36 bytes: 32 bytes of hash id and 4 bytes of checksum. There are 4095 nodes in the 2048-leave small Merkle tree, and they are numbered in such way:

```
                               1                                        
                              /  \                                       
                             /    \                                       
                            /      \                                       
                           /        \                                       
                          /          \                                       
                         /            \                                       
                        2              3                                  
                       / \            / \                                    
                      /   \          /   \                                    
                     /     \        /     \                                    
                    4       5       6      7                             
                   / \     / \     / \    / \                                    
                  /   \   /   \   /   \  /   \                                    
                 8    9  10   11 12  13  14  15
```

Node 1 is the root, and 2 and 3 is its left child and right child. Generally, node `n` has `2*n` and `2*n+1` as its left child and right child. There is no node numbered as 0. The 2048 leaves in the tree are numbered from 2048\~4095.

In the twig Merkle tree file, we also stores the first entry's position of each twig, which shows the postion where we can find the first entry of a twig in the entry file. This information occupies 12 bytes: 8 bytes of position and 4 bytes of checksum.

So totally, a twig uses 12+36\*4096=147468 bytes in the twig Merkle tree file.

### Datatree

See datatree/tree.go

This is most important data structures. Youngest twig, active twigs and pruned twigs are all implemented here. Most of the code are related to incrementally modify the Merkle tree by appending new leaves and deactive old leaves, which are performed in a batch way after each block.

#### Major Components

A datatree keeps the following major components:

1. The entry file
2. The twig Merkle tree file, which stores the left parts of all twigs, except the youngest one
3. The left part of the youngest twig
4. The right parts of all active twigs (the right parts of the inactive twigs are all same)
5. The upper-level nodes whose are ancestors of active twigs

The components 3, 4 and 5 are stored in DRAM and volatile. So to stop moeingads in a friendly way, these components should be serialized and dump to disk, after a block is fully executed. When moeingads is stopped unexpectedly (for example, because of machine crash), the components 3, 4 and 5 will be lost, and their state must be rebuilt from components 1 and 2.

A datatreee also keeps some minor components, which are temporary sratchpad used during block execution. When a block is fully executed, the contents of these components will be cleared.

#### Buffering the right part of youngest twig

The right part of a twig is a Merkle tree with 2048 leaves. When a new twig is allocated as the youngest one, all its leaves are hashes of null entry, whose Key, Value and NextKey are all zero-length byteslices and Height, LastHeight and SerialNum are all -1.

As new entries are append into the youngest twig, more and more leaves are replaced by hashes of non-null entries. And the 2048-leave Merkle tree changes gradually. We record this gradually-changing left part of the youngest twig in the variable `mtree4YoungestTwig`.

After 2048 entries are appended, the right part can not change anymore, so we flush it into the twig Merkle tree file and then allocate a new Merkle tree in `mtree4YoungestTwig`, as the youngest one.

#### Evicting twigs and pruning twigs

When a twig's active bits are all zeros, its right part can not change any more. So we can evict it from DRAM to make space for newly-generated twigs.

The aged twigs will undergo the compaction process, during which the valid entries are read out, marked as invalid and re-append the youngest twigs. Compaction ensures we can always make some progress in evicting old twigs.

Pruning twigs is another operation, which is totally different from evicting. Pruning twigs means prune the entries and left parts of old twigs from hard disk. The twig Merkle tree file and the entry file are all implemented with head-pruneable files, so they support pruning the records at the head.

#### Upper-level nodes

In datatree we use the variable `nodes` to store the upper-level nodes, which are acestors of non-pruned twigs.

The variable `nodes` is just a golang map, which values are hash IDs stored in nodes, and keys are positions. How to present the position of a node in a Merkle tree? If a node is the `N`-th node at level `L`, the its position is calculated as an integer `(L<<56)|N`. A node with postion of `(L, N)` has two children: `(L+1, 2*N)` and `(L+1, 2*N+1)`.

A root node is the node whose level is the largest among all the nodes.

#### The null twig and null nodes

moeingads uses balanced binary Merkle tree whose leave count is $2^N$,. If the count of entries is not $2^N$, we just add null entries for padding, concepturally . In the implementation, we do not really add so many null entries for padding. Instead, we just add at most one null twig and at most one null node at each level. In a null twig, all the active bits are zero and all the leaves are null entries. For a null node, all its descendant (downstream) nodes and twigs are null. The null twig and null nodes are pre-computed in the `init()` function.

In the following figure. E is a null twig while F and G are null nodes. We do not keep the grey portion in DRAM and hard disk, because these twigs and nodes are all null. Instead, storing E, F and G in DRAM is enough to providing proof for every valid entry.

![ADS\_7](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F11eb1587ea32042c75a90b9ea1f0cd8eda7c7163.png?generation=1616929516748908\&alt=media)

#### The edge nodes

In the above figure, the first four twigs are pruned to save space of hard disk. If we discard all the orange portion of the Merkle tree, some entries will be impossible to be proven. So we must still keep the nodes A, B, C and D in DRAM. These nodes are called "edge nodes" because they are at the left edge of the remained tree. A node is an edge node if and only if:

1. It is the twigRoot of just-pruned twig, i.e., whose twigID is the largest among all pruned twigs.
2. It has both pruned-descendants and non-pruned-descendants.

If pruning is performed in a block, then the edge nodes must be saved to database when this block commits, to keep data consistency.

#### Batch sync

The datatree gets changed because of two kinds of operations: appending new entries and deactivating old entries. If we synchronize the Merkle tree after each operation, the amount of computation would be huge. So we prefer to finish all the appending and deactivating operations in a block and then use batch-mode synchronization to make the Merkle tree consistent.

Synchronization has four steps:

1. When the left part of the youngest twig is ready to be flushed to hard disk, this 2048-leave tree get synchronized. This synchronization can run multiple times during a block's execution.
2. When a block finishes execution, the left part of the youngest twig get synchronized.
3. When a block finishes execution, all the right parts of twigs get synchronized.
4. When step 2 and 3 finish, the upper level nodes get synchronized.

During step 2, 3 and 4, the hash computations of the same level are independent with each other, so we can run them parallelly.

### Rocksdb

See indextree/rocks\_db.go

RocksDB is a KV database written in C++. It has a Golang binding, which is not so easy to use. Tendermint wraps the binding for easier use. We refined Tendermint's wrapper to support pruning.

RocksDB supports filtering during compaction, which is a unique feature among all the opensource KV databases. We use this feature in indextree.

In moeingads there is a rocksdb database. Both metadb and indextree use it to store some information which is not performance-critical but important for consistency. All the updates generated during one block is kept in one batch, to make sure blocks are atomic. If the batch commits, the block commits. If the batch is discarded, it looks as if the block does not execute at all.

### metadb

See metadb/metadb.go

We need to store a little meta information when a block finishes its execution. The data size is not large and not performance critical, so we store them in RocksDB.

When moeingads is not properly closed, we should use the information in metadb as guide to recover the other parts of moeingads.

The following data are stored in metadb:

* CurrHeight: the height of the latest executed block
* TwigMtFileSize: the size of the twig Merkle tree file when the block at CurrHeight commits.
* EntryFileSize: the size of the entry file when the block at CurrHeight commits.
* OldestActiveTwigID: ID of the oldest active twig, i.e., this ID is the smallest among all the active twigs.
* LastPrunedTwig: ID of the  just-pruned twig, i.e., this ID is the largest among all pruned twigs.
* EdgeNodes: the edge nodes returned by `PruneTwigs`.
* MaxSerialNum: the maximum serial number of all the entries. When a new entry is appended, it is increased by one.
* ActiveEntryCount: the count of all the active entries.
* IsRunning: whether moeingads is running. When moeingads is initialized, it is set to true. When moeingads is closed properly, it is set to false. If it is found true during  initialization, it means moeingads was NOT closed properly, and you should recover the data.
* TwigHeight: a map whose key is Twig's ID and value is the maximum value of its entries' heights. When moeingads is asked to 'prune till a given height', this map is used to show which twigs can be pruned.

When moeingads is NOT properly closed, TwigMtFileSize and EntryFileSize may be different from the real file size on disk, because of the last block's partial execution. Before recovering, the twig Merkle tree file and entry file would be truncated to the TwigMtFileSize and EntryFileSize stored in metadb, respectively.

### B-tree

We include two B-tree implementations. One is a Golang version from modernc.org/b (indextree/b/btree\_nocgo.go), and the other is a C++ version from Google (indextree/b/cppbtree/btree.go and indextree/b/btree\_cgo.go). Why there are two versions? Because we do not have 100% confidence of either one of them. So we use fuzz test to compare their outputs. If the outputs are the same, then most likely they are both correct, because they are implemented independently and hard to have the same bug.

In production, the C++ version is preferred. Because:

1. The B-Tree will use a lot of memory. The C++ version doesn't use GC, so it will be faster.
2. We can use a trick to save memory when the key's length is 8.

This trick is from the old wisdom of embedded systems. It utilizes the fact that pointers are aligned, that is, the least significant two bits is always zero. So, when the key's length is 8 and the least significant two bits of its first byte is not 2'b00, we do not need to store a pointer to byte array, instead, we can store the byte array within the 8 bytes occupied by a pointer. (Note that x86-64 and ARM64 uses little endian, which means the least significant two bits of an int64 locate in the first byte of an array.)

We use B-Tree because it's much more memory-efficient that Red-Black tree and is cache friendly.

### indextree

See indextree/indextree.go

We implement indextree with an in-memory B-Tree and a on-disk RocksDB, which is shared with metadb. The B-Tree contains only the latest key-position records, while the RocksDB contains several versions of positions for each key. The B-Tree's keys are original keys while the keys in RocksDB have two parts: the original key and 64-bit height. The height means the key-position record expires (get invalid) at this height. When the height is math.MaxUInt64, the key-position record is up-to-date, i.e., not expired.

When we execute the transactions in blocks, only the latest key-position records are used, which can be queried fast from in-memory B-tree. The RocksDB is only queried when we need historical KV pairs. But, during executing the transactions, the RocksDB is written frequently, which is also an overhead. So if you do not care about historical KV pairs, you can turn off this feature.

The RocksDB's content is also used to initialize the B-Tree when starting up. When height is math.MaxUInt64, the KV pair is up-to-date and must be inserted to the B-Tree.

If we no longer need the KV-pairs whose expiring height are old enough, they can be filtered out during compaction: this is how pruning works.

### Top of moeingads

See moeingads.go

It integrates the three major parts and implement the basic read/update/insert/delete operations. The most important job of it is to keep these parts synchronized. It uses a two-phase protocol: during the execution of transactions, it perform parrallel prepareations to load "hot entries" in DRAM; when a block is committed, it updates these parts in a batch way.

During a block's execution, we say an entry is "hot" when:

1. It may be a newly-inserted entry
2. Its Value may be updated
3. Its NextKey may be changed because a new entry will be inserted next to it.
4. Its NextKey may be changed because the entry next to it may be deleted

We use the word "may" here because in individual transaction in a block may succeed or fail during execution. If it succeed, the KV updates made by it will take effect. If it fail, the KV updates will be discarded.

To support parallel execution of transactions, we use a `sync.Map` to cache the hot entries. This cache is valid only during a block's execution. When a block commits, it is cleared.

During a block, this cache undergoes a filling phase, a marking phase and a sweeping phase. In the filling phase, many transactions can concurrently add new hot entries to this cache, using the `PrepareForUpdate` and `PrepareForDeletion` functions. In the marking phase, only the succeeded transactions marking some of these hot entries to be inserted, changed or deleted, using the `Set` and `Delete` functions. In the sweeping phase, the cached hot entries are sorted according to their keys and then we scan these sorted hot entries to update datatree.

## Store Data Structures

The API of moeingads is somehow hard to use because you must follow the three phases of the hot entry cache. It would be better to wrap it with some "store" data structures to provide an easy-to-used KV-style API. The figure below shows the relationship among these "store" data structures.

```
  PrefixedStore
         |
         |
    MultiStore
      |      \
      |       \
   TrunkStore  \
      |   \     \
      |    \     \
  RootStore \     \
      |     CacheStore
      |
   moeingads
```

There are three levels of caching with different lifetimes: RootStore's cache lasts for many blocks, TrunkStore's cache only exists during a block and MultiStore's cache only exists during a transaction.

During run time, the relationship of these stores are shown as below.

![ADS\_8](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F3ea8128d4de47d7d8aa9196941b16644b783c106.png?generation=1616929516604804\&alt=media)

Each transaction has its own MultiStore, based on which there are several PrefixedStore. Each transaction's MultiStore can access the block's TrunkStore. When block is committed, contents in TruckStore are flushed to RootStore.

The transactions in a block are divided into several epochs. Inside an epoch, transactions are independent, and among epochs, they are dependent. So we execute all the transactions of one epoch in parallel, and then switch to the next epoch when finished. This algorithm's detail is show below:

1. Allocate a new TrunkStore for a new block
2. Fetch an epoch of transactions from the block
3. Execute these transactions in parallel, which read and write their own MultiStore, and at the same time, read the shared TruckStore and RootStore
4. For the succeeded transactions, flush their caches to TrunkStore, and for the failed ones, discard their caches.
5. Repeat step 2 to 4 until there are no more epochs
6. Flush the TrunkStore's cache to root cache

### Lazy Serialization

The values stored in the caches are serializable objects, instead of plain byteslices.

```go
type Serializable interface {
    ToBytes() []byte
    FromBytes([]byte)
    DeepCopy() interface{}
}
```

Serializable objects allow "lazy serialization". These objects undergo serialization/deserialization only when they are read out from and written to the entry file. When being transferred among these caches and the application's logic, they are just plain pointers.

The stores all support serializable objects. They are so-called "Key-Object stores", instead of plain "Key-Value stores". They support following `Get*` functions:

* Get: return the serialized byteslices of the object
* GetObjCopy: return a deep copy of the object
* GetReadOnlyObj: return the object itself, but the transaction should not modify the object

The MultiStore and PrefixedStore only serves one transaction, so they can support one more function:

* GetObj: return the object itself, and record that this object's ownership is transferred out. The client code cannot use GetObj twice at the same key, and the code must use SetObj to return back the ownership later.

RootStore and TrunkStore cannot support GetObj because the object's ownership will never be returned back if the transaction fail.

### CacheStore

See store/cache.go.

It uses the Golang version of B-tree to implement an in-memory cache for overlay. It buffers all the changes to the underlying store, including value-updating, insertion and deletion. `ScanAllEntries` can iterate all these buffered changes. It is used to dump these changes to the underlying store.

CacheStore shadows (overrides) the underlying store. If a key hits on the cache, then the cached status (existence and value) will take precedence over the underlying store.

CacheStore's iterator does not skip deleted keys. Instead, it returns a nil key to signal it is pointing to an deleted item.

A cacheMergeIterator merges a parent Iterator and a cache Iterator, and provides a clear interface to outside. If the cache iterator has the same key as the parent, the cache shadows (overrides) the parent.

### RootStore

See store/root.go.

It survives many blocks to provide persistent cache for frequently-reused data. Its cache is just a plain golang map `map[string]Serializable`. Its cache is not used to add an overlay. Instead, it is more like a file system cache in memory to avoid reading entries from hard disk. It only caches readonly objects, such as parameters which can be configured by proposals. You can further control which readonly objects can be cached by providing `isCacheableKey func(k []byte) bool`, which returns true for keys whose value need to be cached.

### TrunkStore

See store/truck.go.

It is for one block's execution, with a cache overlay. When a TrunkStore is closed, you can choose to write back its contents or not. Once the write-back process starts, it cannot be read or written any more.

### MultiStore

See store/multi.go.

It is for one transaction's execution, with the cache overlay. It is named as "multi" because there are multiple MultiStores built upon a TrunkStore. When a MultiStore is closed, you can choose to write back its contents or not. Normally, the MultiStore is write back when a transaction succeeds.

### PrefixedStore

See store/prefix.go.

It helps to divide a MultiStore into several "sub stores", each one of which has a unique key prefix. Every operation on PrefixedStore, will be performed on the underlying MultiStore, with the keys be prefixed.


# Benchmarking MoeingADS

MoeingADS is the most important corner stone of Smart Bitcoin Cash. MoeingADS puts an upper bound for Smart Bitcoin Cash's throughput. You may want to know, when ignoring all the other factors (consensus engine, smart contract execution, etc) and only having MoeingADS in the critical path, how high can the throughput reach? Because no matter how hard we optimize the other parts of Smart Bitcoin Cash, its throughput cannot get higher than this upper limit.

Let's suppose there is a chain named "Extreme Stable Coin Chain" (ESC Chain). Its characters include:

1. It uses EOS-style DPoS consensus algorithm. A super node generates 100 blocks and then the next super node takes turn.
2. It does not support smart contracts.
3. It has one native token to pay gas fee and several other types of stable coins.
4. The amounts of coins are represented as 256-bit integers.
5. One account can own at most 8 types of stable coins.
6. The only transaction type is sending one kind of stable coin or the native token to another account, while deducting sender's native token as gas fee.

When producing a block, a super node 1) collects the incoming transactions sent through P2P network, 2) execute the transactions and update the world state, 3) packs the executed valid transactions into blocks. Clearly these three steps can be pipelined and the second step is the most time consuming. The other two stages in the pipeline, step 1 and step 3, can hide their latency behind step 2.

By the way, although ESC Chain is rather simple, it is not a toy. If someone fully implements it and persuade WalMart, Amazon, Steam, Reddit and Twitter to use it, it would be a big business.

## What the benchmarks do

We are not implementing ESC chain here. We just write benchmarks to mimic what is done in the most time consuming step 2. These benchmarks are enough to show how fast ESC chain can run.

The benchmarks simulate such a system: there are totally 100 stable coins, and $n$ accounts, each of which has 1\~8 types of coins. The coins' amounts are initialized with random numbers. In each transaction, one account sends some amount of stable coin to another account. The amounts are chosen randomly but with constraints, such that the amounts do not overflow or underflow after sending, which means all the transactions are valid. In each transaction, 10 native tokens are deducted from the sender's account as gas fee, and the sender's sequence number is increased by one to prevent replay attacks. The transactions' digital signatures are not checked in the benchmark, because this task can be easily offloaded to other CPUs or other machines.

The benchmarks are:

1. **genacc**: it generates $n$ random accounts into the system. The generating process will continue for $n/20000$ blocks and during each block 20000 random accounts are generated.
2. **checkacc**: it reads the $n$ generated accounts out, in a randomized order. It can show the QPS (queries per second) MoeingADS can support.
3. **runtx**: it runs $m$ blocks, and each block has 128K random valid transactions. It can show the TPS (transactions per second) MoeingADS can support.

## How to run the benchmarks

The test machine must have 32GB DRAM and about 800GB free SSD space. Such a machine can also run an go-ethereum client smoothly. The OS must be Linux or MacOS (Windows is not supported) and please install [golang](https://golang.org/doc/install) and [rocksdb](https://github.com/facebook/rocksdb/blob/master/INSTALL.md) beforehand. You can follow this [guide](https://github.com/smartbch/docs/blob/master/developers-guide/build-smartbchd.md) to install them. The machine used in this article is m6gd.4xlarge instance, with 16 vCPUs, 64GB DRAM and 900GB SSD.

Step 0: check out the benchmarks' code and build executable.

```bash
$ mkdir ~/benchmark; cd ~/benchmark
$ git clone https://github.com/smartbch/moeingads
$ cd moeingads/store/escchainbench
$ go build -tags cppbtree
```

After executing above commands, you'll have an executable file named `escchainbench` in the current directory.

Step 1: set some parameters.

```bash
$ export RANDFILE=path-to-a-large-file
$ export ACCNUM=$((841*1000*1000))
$ export BLKCOUNT=2000
```

RANDFILE is a large file used as random seeds. You can use a compressed archive file or a video file. ACCNUM is the total number of generated accounts in the simulated system. It's set to 841 million, which is roughly the population of European Union. BLKCOUNT is the number of blocks will be executed in the TPS test.

Step 2: generate the accounts randomly.

```bash
$ time -v ./escchainbench genacc $ACCNUM |tee gen.log
```

We use the `time` command to record how much DRAM is used by the benchmark.

On m6gd.4xlarge, `genacc` takes 12291 seconds to create the 841 million accounts and the maximum resident set in DRAM is 15.5GB. Averagely 68424 accounts can be created in one second.

Step 3: test the query speed.

```bash
$ time -v ./escchainbench checkacc $ACCNUM |tee check.log
```

On m6gd.4xlarge, `checkacc` takes 1705 seconds to read all the 841 million accounts, averagely 493K queries per second.

Step 4: test the transaction execution throughput (TPS).

```bash
$ time -v ./escchainbench gentx $ACCNUM $BLKCOUNT |tee gentx.log
$ time -v ./escchainbench runtx $BLKCOUNT |tee runtx.log
```

First, `gentx` generates blocks of random transactions and then `runtx` executes these transactions. After this step, the data base's size is 664GB.

On m6gd.4xlarge, `runtx` takes 1043 seconds to load data from SSD and takes 5103 seconds to execute the 2000\*128\*1024=262144000 transactions and the maximum resident set in DRAM is 16.8GB. The TPS is 262144000/5103=51370. If each transaction costs 21000 gas (the intrinsic gas of an Ethereum transaction), then in 15 seconds 16.2 billion (21000\*51370\*15) gas can be consumed.

The `time` command shows "Percent of CPU this job got" is 558%. Since the instance has 16 vCPUs, it allows the system to further exploit hardware's parallelism, for example, the step 1 and 3 running in parallel with step 2.

A block on Ethereum can consume at most 15 million gas in 15 seconds. So ESC chain is about 1080 times faster than ethereum in payment.

## Conclusion

We present a conceptual chain named ESC (Extreme Stable Coin) chain which focuses on stable coin payment. Benchmarks show that when built on MoeingADS, ESC chain can consume 16.2 billion gas in 15 seconds, which is 1080 times faster than Ethereum.

ESC chain is an application-specific chain without smart contract support. Smart Bitcoin Cash is more powerful and thus has overhead. We do not expect it can run as fast as ESC chain. But 16.2 billion gas gives us enough confidence that Smart Bitcoin Cash can achieve the "one billion gas every 15 seconds" target.


# Benchmarking MoeingEVM and MoeingADS

After benchmarking the MoeingADS using [ESC Chain](/smartbch/in-depth-design-documents/benchmarking-moeingads), which can only send tokens, you may be curious about how it performs on smart contracts. So now we introduce how to run benchmarks to test the performance of calling smart contracts with MoeingEVM and MoeingADS.

We simulate such a scenario that 100% of CPU resource is used for verifying the transactions in blocks. As Vitalik Buterin [pointed out](https://vitalik.ca/general/2021/05/23/scaling.html), it is better for a node to put only 10% of CPU resource in verifying blocks. So if we want to reach the "one billion gas every 15 seconds" target, we'd better make sure the performance of solely verifying blocks can reach about 10 billion gas every 15 seconds.

We use the following simple contract for benchmarking, because its behavior is quite easy to understand. You can find it at <https://github.com/smartbch/smartbch/blob/main/testdata/basic/contracts/Stress.sol>

```solidity
pragma solidity >=0.7.0;

contract Stress {
    mapping(uint32 => uint) private data;

    function run0(address to, uint32 offset) payable external {
        to.call{value: msg.value, gas: 9000}(new bytes(0));
        for(uint32 i = offset; i < offset + 10; i++) {
            data[i] = msg.value/3;
        }
    }

    function run(address to, uint256 param) payable external {
        to.call{value: msg.value, gas: 9000}(new bytes(0));
        uint32 a = uint32(param>>(32*0));
        uint32 b = uint32(param>>(32*1));
        uint32 c = uint32(param>>(32*2));
        uint32 x = uint32(param>>(32*3));
        uint32 y = uint32(param>>(32*4));
        uint32 z = uint32(param>>(32*5));
        data[c] = (data[a] + data[b] + msg.value)/2;
        data[z] = (data[x] + data[y] + msg.value)/2;
    }

    function run2(address to, address addr1, address addr2, uint256 param) payable external {
        to.call{value: msg.value/2, gas: 9000}(new bytes(0));
        uint32 a = uint32(param>>(32*0));
        uint32 b = uint32(param>>(32*1));
        uint32 c = uint32(param>>(32*2));
        uint32 x = uint32(param>>(32*3));
        uint32 y = uint32(param>>(32*4));
        uint32 z = uint32(param>>(32*5));
        data[c] = (data[a] + data[b] + msg.value)/2;
        data[z] = (data[x] + data[y] + msg.value)/2;
        Stress(addr1).run{value: msg.value/3}(addr2, param);
        Stress(addr2).run{value: msg.value/9}(addr1, param);
    }

    function get(uint32 d) external view returns (uint) {
        return data[d];
    }
}
```

The gas consumption of calling the functions is not fixed. When new storage slots are created, the gas consumption is high and when only existing slots get updated, the gas consumption is low.

The benchmark's source code can be found at <https://github.com/smartbch/smartbch/blob/main/cmd/stresstest/stress.go> .

We selected four instances on AWS for the benchmark:

1. r6gd.2xlarge: Amazon Graviton2 Processor, 8 vCPUs, 64GB DRAM, 475GB SSD
2. m6gd.2xlarge: Amazon Graviton2 Processor, 16 vCPUs, 64GB DRAM, 950GB SSD
3. c6gd.2xlarge: Amazon Graviton2 Processor, 32 vCPUs, 64GB DRAM, 1900GB SSD
4. m5ad.4xlarge: AMD EPYC Processor, 16 vCPUs, 64GB DRAM, 600GB SSD

Now let's run this benchmark. The whole process takes more than 20 hours, so please be patient.

Step 0: please follow [this document](https://github.com/smartbch/docs/blob/master/developers-guide/build-smartbchd.md) and finish all the steps.

Step 1: generate some random private keys into the file "keys60M.txt":

```bash
cd ~/smart_bch/smartbch/app/stresstest
go run -tags cppbtree . genkeys60
```

Step 2: generate several blocks filled with random transactions:

```bash
ulimit -n 60000
RANDFILE=~/go1.16.3.linux-amd64.tar.gz  go run -tags cppbtree . gen |tee gen.log
```

Step 3: replay the transactions in the generated blocks:

```bash
go build -tags cppbtree .
rm -rf testdbdata
/usr/bin/time -v ./stresstest replay |tee replay.log
```

The generated transactions can be categorized into three groups:

1. Deploy the smart contracts
2. Initialize the storage slots and the target addresses, using the `run0` function
3. Transfer random amount of BCHs to the randomly-selected target addresses and overwrite some storage slots randomly, using the `run2` function

The benchmarks are written in such a way that transactions in group 2 always create new storage slots while transactions in group 3 always overwrite existing storage slots. Most real transactions' behavior is at some position in between: they both create new slots and overwrite existing slots.

These three groups of transactions are carried out in sequence. We care about the performance of group 3 and the last part of group 2. Because when these transactions get executed, MoeingADS has already taken a lot of SSD space (200GB+) which is too large for OS to cache it in DRAM.

The gathered results are:

| CPU          | Performance of Group 3 (billion gas per second) | Performance of Group 2 (billion gas per second) |
| ------------ | ----------------------------------------------- | ----------------------------------------------- |
| r6gd.2xlarge | 0.21                                            | 0.57                                            |
| m6gd.4xlarge | 0.34                                            | 0.86                                            |
| c6gd.8xlarge | 0.43                                            | 1.01                                            |
| m5ad.4xlarge | 0.29                                            | 0.77                                            |

When CPU count increases from 8 to 16, the speed-up is obvious; but when from 16 to 32, the speed-up is not so obvious. This is because there are some jobs which cannot be parallelized.

We can see that 16 Graviton2 vCPUs are faster than 16 EPYC vCPUs. This is because a vCPU of Graviton2 is a physical core, while a vCPU of EPYC is just one thread of the two threads running on a physical core.

According the results, m6gd.4xlarge has the best price/cost: it burns 5.1\~12.9 billion gas in 15 seconds, and its price is lower than m5ad.4xlarge.


# Benchmarking Testnet

Although MoeingADS and MoeingEVM are important libraries, what we most care about is always the performance of the whole blockchain, instead of its individual components.

To benchmark MoeingADS and MoeingEVM, we have developed some toolkits to generate random transactions and run them. They can also be used to benchmark the entire chain. You can find their source code at <https://github.com/smartbch/smartbch/blob/main/cmd/stresstest> .

First, we follow the sames steps as [the benchmarks](/smartbch/in-depth-design-documents/benchmarking-moeingevm-moeingads) for MoeingADS and MoeingEVM, till the end of Step 2 (generate several blocks filled with random transactions). There will be a generated directory named `blkdata`, which contains the random transactions; and a `keys60M.txt` file, which constains some test keys.

Then, we need to start [a multi-node testnet](/smartbch/archives/runmultinode) or [a single-node testnet](/smartbch/archives/runsinglenode) first. Please note that we must give enough initial balances to the first 50,000 accounts in the `keys60M.txt` file, such that they can send transactions.

Now we can use a node's websocket to broadcast these random transactions:

```bash
./stresstest replayWS ws://the-ip-address-of-a-smartbch-node:8546 
```

Finally we can query about the status of executed transactions:

```bash
./stresstest queryTxsWS ws://the-ip-address-of-s-smartbch-node:8546 <stop-height>
```

Or we can draw some charts showing the chain's performance:

```bash
./stresstest queryBlocksWS ws://the-ip-address-of-s-smartbch-node:8546 <stop-height> <start-height> true
```

After running above commands, there will a `charts.html` file in current directory showing the following numbers in every 100 blocks: 1, Transaction Count; 2, Block Size; 3, Used Gas; 4, Block Interval.


# Transaction Reordering in smartBCH

Ethereum's mining pools can decide the exact transaction order in a block. The mining pools prefer to pack a bundle of more profitable transactions. This opens the door of "front-running", such as the "[sandwich attacks](https://cmichel.io/de-fi-sandwich-attacks/)" towards uniswap.

In smartBCH, the order in which transactions take effects are different from the order specified by the validator who proposes the block. Instead, they are reordered by a deterministic algorithm, to meet two goals:

1. Maximize the execution parallelism among transactions
2. Mitigate the problem of front-running

To meet goal #1, slight adjustment to the transaction order is enough for most of the cases. To meet goal #2, the orders must be reordered thoroughly in a pseudo random way.

In smartBCH's golang implementation, the transaction list is pseudo-randomly shuffled after it is got from a new committed block, and before it is further processed and stored into the node's local storage. In the transaction list there may be multiple transactions from the same account, whose nonces are in an increasing order. We must keep the partial order of the transactions from the same account, to make sure the transactions will be executed in a nonce-increasing order.

The pseudo-random shuffle algorithm has following steps:

1. Get a from-address list and a from-address-to-transactions 1-to-n map from the transaction list
2. Calculate the seed for pseudo random generator, using  the current block's DataHash (the Merkle root of transactions)
3. Shuffle the from-address list using the pseudo random number sequence generated by the algorithm [MT19937-64](https://en.wikipedia.org/wiki/Mersenne_Twister).
4. Get a shuffled transaction list using the from-address list and the from-addrss-to-transactions map

In the shuffled transaction list, the transactions from the same address are adjacent, but they are not executed back-to-back. Actually, during execution, in an enforced bundle we only execute the first one of the several transactions from the same address and the others will be put to the end of standby list and get executed at the very last.

If a malicious validator want to enforce several partial orders among several specific transactions, its must try different transaction sets and thus different seeds for pseudo random generator, and see which one leads to an expected order. As the number of partial orders it wants to enforce increases, the computation needed for trying different seeds increases exponentially.

In the future, [VDF](https://blog.trailofbits.com/2018/10/12/introduction-to-verifiable-delay-functions-vdfs/) will also be used to generate the seed for pseudo random generator, which can reduce the time window in which a malicious validator can try different seeds.


# Transaction Parallel Execution in smartBCH

In this article, we describe how multiple transactions are executed in parallel, and how the execution engine and the consensus engine work concurrently.

## Execution Engine and Consensus Engine

Tendermint is the consensus engine of smartBCH, and it takes the charge of proposing new blocks and voting for them. And smartBCH's execution engine is a state machine: it takes committed blocks from tendermint as input, updates the world state accordingly and outputs logs and transaction\&block records.

The block interval can be divided into two phase: committing phase and post-commit phase. The committing phase begins when tendermint collects enough voting power for the next block, and ends when the execution engine returns the AppHash (Merkle root of world state) back to tendermint.

During the committing phase, tendermint does the following job:

1. Collect more votes and try to reach 100% vote power for the next block (100% is not preferred but not required)

During the post-commit phase, tendermint does the following job:

1. Use the returned AppHash and accumulated transactions in mempool to propose a new block
2. Broadcast and vote for the new block
3. When the voting power reaches 2/3, feed the new block to the execution engine

During the committing phase, the execution engine does the following job:

1. Preprocess the transactions in the new block
2. Save the valid transactions into standby queue (which is part of the world state)
3. Calculate AppHash

During the post-commit phase, the execution engine does the following job:

1. Fetch transactions out from the standby queue
2. Execute the transactions in parallel
3. Update the world state according to the successfully committed transactions

In practice the committing phase is more time-consuming, especially when there are a lot of transactions and a lot of validators. By making the two engines concurrently do their jobs, more transactions can be executed and more votes can be collected.

## Transaction handling in the committing phase

The committing phase can be divided into four sub-phases.

In the first sub-phase, the transactions are parallelly checked for:

1. Whether the signature is valid
2. Whether the from-account exists.
3. Whether the gas limit is under the upper limit
4. Whether the gas price is higher than the minimum price

In the second sub-phase, the transactions are pseudo-randomly reordered. The detailed algorithm is described [here](/smartbch/in-depth-design-documents/tx-reorder).

In the third sub-phase, the reordered transactions are parallelly processed:

1. If the transaction's nonce does not match the from-account's nonce, mark it as invalid
2. Deduct the gas fee from the from-accounts, which is calculated as `GasPrice*GasLimit`. The nonce of from-accounts are NOT modified here.

In the last sub-phase, all the valid transactions are saved into the standby queue, and AppHash is calculated from the latest world state.

## Transaction handling in the post-commit phase

In this phase transactions are handled in several "rounds". At each round, following tasks are done：

1. Load at most $N$ transactions from the standby queue
2. Execute these transactions concurrently and independently. For each transaction,
   1. Execute it in an isolated context which buffers all its modifications to the world state. The nonce of from-account is updated here.
   2. After execution, refund the unused gas fee back to the from-address, and the refund amount is calculated as `GasPrice*(GasLimit-GasUsed)`
3. Analyze these transactions' dependency one by one and decide whether each transaction can be committed:
   1. If it can be committed, write its modification to the world state
   2. If not, insert it back to the end of the standby queue

For each block, at most $M$ rounds will be run. If there are too many transactions in the standby queue, they cannot be finished in one block. In some cases, a transaction will be executed several blocks after it is added to the standby queue. But if a transaction has been kept in the standby queue for more than $L$ blocks, it will be marked as "executed as a nop"

How to analyze the dependency? Since the world state is just a set of key-value pairs, we just keep a "touched key set" of the pairs which were updated by previous committed transactions. The next transaction can commit if and only if it never read or write a pair whose key is in the set. For the different kinds of key-value pairs in the world state, please refer to [data structures in world state](/smartbch/in-depth-design-documents/data-structures-in-world-state).


# Send back-to-back Transactions

On Ethereum, sometimes Alice may want to do such a job:

1. Prepare three transactions for arbitrage at an earning smart contract:
   1. The first transaction: sell a lot of assets to lower the price
   2. The second transaction: deposit another asset at the lower price
   3. The third transaction: buy back the assets sold at the first transaction
2. Sign these three transactions with increasing nonces and a high enough gas price
3. Send them to the p2p network without any time interval between them

Then Alice assumes these transactions will be placed back-to-back (without any other transactions among them) in the mempool and eventually they will be also packed back-to-back into a block and get executed in sequence, without any other transactions cutting into.

Can such a developer successfully do the same job on smartBCH? Unfortunately, no. On smartBCH, the only partial order of the transactions sent from the same account with increasing nonces is enforced. You cannot ensure they never get cut in by other transactions. And you cannot assume they will be packed into the same block, or into successive blocks.

Because of [transaction reordering](/smartbch/in-depth-design-documents/tx-reorder), the transactions from a new block are shuffled before execution, and in an enforced bundle, only one transaction for an address gets executed while the others are put to the tail of the standby queue.

Although the sequence of transactions from different accounts is not ensured, transaction reordering keeps the relative positions between the transactions from the same account. Furthermore, smartBCH's full-node client allows Alice's successive transactions to enter mempool smoothly, with some limitations:

* If in block N's interval, Alice has one or more transactions entering mempool and/or getting packed into a block:
  * Then, in block N+1's interval, the total gas limit of all the transactions which are sent into mempool by Alice must be no larger than 5,000,000.
* Or else (In block N's interval, Alice has no transaction):
  * Then, in block N+1's interval, the first transaction sent by Alice can specify any gas limit.
  * The total gas limit of all the following transactions from Alice must be no larger than 5,000,000.

In most cases, if you are just sending several transactions manually through a wallet such as MetaMask, every transaction will be accepted into mempool, even when some of them have not been packed into a block yet.

But if you are sending a lot of transactions using a script, when the mentioned 5,000,000 gas limit may block some of them. In such cases, we suggest using a dedicated smart contract to batch all the needed contract calls.


# Data structures in world state

In this article, we describe the different kinds of key-value pairs which are stored in smartBCH's world state.

In the following descriptions, we use "+" to denote concatenation.

## Basic Information of an Account

Key: byte(23) + 20-byte-address

Value:

1. 32-byte Balance (Big Endian)
2. 8-byte Nonce (Big Endian)
3. 8-byte Sequence (Big Endian). For EOA, the sequence is always uint64(-1). For contract account, the sequence is assigned a unique value when created.

## Creation Counter

Key: byte(21) + first-byte-of-address

Values: 8-byte Counter (Big Endian)

All the smart contracts who have the same value in the first byte of address share one counter. Each time a new contract is created, this counter get increased by one. And the address of the new contract is calculated by: new-value-of-counter \* 256 + first-byte-of-address.

## Storage in Smart Contract Accounts

Key: byte(27) + 8-byte-account-sequence + 32-byte-key

Value: Non-zero-length byte string (not required to be 32 bytes)

Please note after a smart contract's self-destruction, there will never be another contract which can have the same account sequence as it. So the self-destructed contract's storage slots can never be accessed.

## Bytecode

Key: byte(25) + 20-byte-address

Value: arbitrary-length byte string

EOA has no bytecode. We only store byte codes for smart contracts.

## Standby Queue's Start\&End Positions

Key: byte(102)

Value:

1. 8-byte start position (Big Endian)
2. 8-byte end position (Big Endian)

You can find a standby transaction at a position in the range \[start, end)

## Standby Queue's Content

Key: byte(100) + 8-byte-position

Value: serialized bytes for a transaction

## Current Block's basic information

Key: byte(29)

Value: serialized bytes of current Block's basic information


# SEP101: Store values with arbitrary length

* \[SEP-101: Store values with arbitrary length]\(#store values with arbitrary length)
  * [1. Summary](#1--summary)
  * [2. Abstract](#2--abstract)
  * [3. Motivation](#3--motivation)
  * [4. Status](#4--status)
  * [5. Specification](#5--specification)
    * [5.1 Storage Agent Contract](#51-storage-agent-contract)
      * [5.1.1 Methods](#511-methods)
        * [5.1.1.1 set](#5111-set)
        * [5.1.1.2 get](#5112-get)
      * [5.1.2 Gas Cost](#512-gas-cost)
  * [6. License](#6-license)

## 1. Summary

This SEP proposes a method to store values with arbitrary length, through a pseudo smart contract.

## 2. Abstract

EVM's SSTORE and SLOAD instructions access 256-bit words. At some cases, we want to store more data in a single storage slot. If we add more EVM instructions to support arbitrary-length data loading and storing, compatibility would be hurt. So a pseudo smart contract is preferred. This smart contract is psuedo because it is not implemented by EVM bytecode. Instead, it is supported natively in the full client, smartbchd. So it can directly use MoeingADS's arbitrary-length data storage. It has a predefined address: 10002.

## 3. Motivation

This proposal specifies the behavior of functions in this psuedo smart contract, such that developers can use it correctly.

## 4. Status

This SEP has been implemented since genesis.

## 5. Specification

### 5.1 Storage Agent Contract

From the caller's view, the storage agent contracts behavior is like delegated calls to the following contract:

```solidity
pragma solidity 0.6.12;

contract StorageAgent {
    bytes[0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff] private data;
    function set(bytes calldata key, bytes calldata value) external {
        data[uint256(sha256(key))] = value;
    }
    function get(bytes calldata key) external view returns (bytes memory) {
        return data[uint256(sha256(key))];
    }
}
```

When developing smart contracts with an EVM implementation which does not support SEP101 (such as Ganache), developers can use this contract to mimic the native storage agent.

The underlying mechanism of the native storage agent is different with above solidity code. It directly uses MoeingADS's arbitrary-length data storage, so a `bytes` value does not take several storage slots. Instead, it only takes one slot whose location is calculated as `uint256(sha256(key))`. You can read its variable-length value with `eth_getStorageAt`.

The smart contract 10002 can only be invoked by `delegatecall` and `callcode`. `staticcall` and `call` are not allowed. In other words, the storage inside it cannot be written.

Please not the `key` passed to smart contract 10002 will be hashed into a 256-bit word using sha256 algorithm, and this word is the slot where `value` is stored. Solidity uses small integers and keccak256-hashed words as storage slots, so sha256-hashed words will not conflict with them.

External owned accounts cannot call smart contract 10002, because they are not smart contracts and have no storage slots.

#### 5.1.1 Methods

**5.1.1.1 set**

```
function set(uint key, bytes calldata value) external;
```

Given a 256-bit key and arbitrary-length value, this function stores this key-value pair for the caller.

**5.1.1.2 get**

```
function get(uint key) external view returns (bytes memory);
```

Given a 256-bit key, this function returns the value kept for the caller. If no corresponding key-value pair was stored before, this function returns zero-length byte slice.

#### 5.1.2 Gas Cost

Calling the `set` (`get`) method with values shorter or equal to 32 bytes, costs the same gas as SSTORE (SLOAD) instruction, respectively.

If the value is longer than 32 bytes, extra gas must be paid, which is calculated as: `(value_length - 32) * COST_PER_BYTE`. For the `set` (`get`) method, `COST_PER_BYTE` equals 75 (25), respectively.

## 6. License

The content is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/).


# SEP102: Adjustment of Used Gas

* [SEP-102: Adjustment of Used Gas](https://docs.smartbch.org/smartbch/smartbch-evolution-proposals-seps/pages/-MdPR6RTipqarNi9_Pza#adjustment%20of%20used%20gas)
  * [1. Summary](/smartbch/smartbch-evolution-proposals-seps/sep-102#1--summary)
  * [2. Abstract](/smartbch/smartbch-evolution-proposals-seps/sep-102#2--abstract)
  * [3. Motivation](/smartbch/smartbch-evolution-proposals-seps/sep-102#3--motivation)
  * [4. Status](/smartbch/smartbch-evolution-proposals-seps/sep-102#4--status)
  * [5. Specification](/smartbch/smartbch-evolution-proposals-seps/sep-102#5--specification)
  * [6. License](/smartbch/smartbch-evolution-proposals-seps/sep-102#6-license)

## 1.  Summary

This SEP proposes an algorithm to adjust the used gas considering the real used gas and user-specified gas limit.

## 2.  Abstract

In ethereum, at the beginning of a transaction, all the gas fee (`gas_limit * gas_price`) is deducted from the sender's balance. When it is finished, some gas fee (`gas_remained * gas_price`) is returned to the sender. So the sender effectively pays `gas_used * gas_price` to the network, where `gas_used = gas_limit - gas_remained`.

Here we propose a different way to calculate the returned fee, which also means chances to the fee that the sender effectively pays.

## 3.  Motivation

Unlike go-ethereum, smartBCH's validator just packs all the transactions into block and propose it. The transactions are not executed before the block is proposed. Thus we can do the tx-reordering and parallel execution: the exact tx ordering is not decided until every node gets the transactions. So when a validator proposes a block, it does not know the exact gas consumption of the transactions. But we do need to set a block level gas consumption upper bound, such that a block does not takes too long to execute.

So, in smartBCH, the block's total gas limit is the threshold of the sum of all the transactions' gas limit, which is different from ethereum, where it is the sum of all the transactions' real used gas. Since the senders can specify a very high gas limit for the transactions which only use a small amount of gas, a block may only contain a small number of transactions with high gas limit, which stops the other transactions get packed into block.

So we must encourage users to estimated their transactions' gas consumptions more accurately and make sure the transaction's gas limit is close to the gas it really consumes. If your gas limit is not a good estimation of the actual gas consumption, there will be some penalty.

## 4.  Status

This SEP has been implemented since genesis.

## 5.  Specification

When transactions finish their execution, the returned gas fee is calculated as the following pseudo code:

```
gas_used = gas_limit - gas_remained
if gas_used * 4 < gas_limit then /*the estimated gas consumption is more than four times of real gas consumption*/
    gas_used = gas_limit /* no gas fee will be returned*/
else if gas_used * 2 < gas_limit then /*the estimated gas consumption is more than two times of real gas consumption*/
    gas_used = (gas_used + gas_limit) / 2
else then /*the estimated gas consumption is no larger than two times of real gas consumption*/
    /* return the gas fee just as ethereum*/
endif
returned_gas_fee = (gas_limit - gas_used) * gas_price
```

## 6. License

The content is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/).


# SEP109: On-chain Verification of Verifiable Random Functions

* [SEP-100: On-chain Verification of Verifiable Random Functions](#on-chain-verification-of-verifiable-random-functions)
  * [1. Summary](#1--summary)
  * [2. Abstract](#2--abstract)
  * [3. Motivation](#3--motivation)
  * [4. Status](#4--status)
  * [5. Specification](#5--specification)
  * [6. License](#6-license)

## 1. Summary

This SEP specifies a precompiled contract which can verify VRFs (Verifiable Random Functions).

## 2. Abstract

A [Verifiable Random Functions](https://tools.ietf.org/id/draft-irtf-cfrg-vrf-06.html) is the public-key version of a keyed cryptographic hash. Only the holder of the private key can compute the hash, but anyone with public key can verify the correctness of the hash. It is very hard to implmenent VRF using EVM's bytecode, since VRF needs a lot of computations on eliptic curves. So on smartBCH, we implement VRF using the native language (Golang) and expose its interface as a precompile contract, which has a predefined address: 10003.

## 3. Motivation

Verifiable random functions are very useful in electing a random quorum in a fair way. They have been used in some blockchains, such as Algorand, VeChain and harmony.one.

If smart contracts can support VRFs, on-chain governance can also use them in electing quorems, which will benefit smartBCH's ecosystem.

## 4. Status

This SEP was already deployed at the XHedge upgrade.

## 5. Specification

The smart contract at the address of 0x0000000000000000000000000000000000002713 can verify VRFs. It takes a byte string as input, which contains the following information:

1. `Alpha` (byte 0\~31), this is the preimage to be hashed. Although IETF's standard allows variable-length alpha, on smartBCH only fixed length preimages are supported.
2. `Public Key` (byte 32\~64), this is a 33-byte compress public key for the secp256k1 curve.
3. `Pi` (bytes 65\~end), this is the proof for hashing.

It returns 32-byte output data and a status code. When `Public Key` and `Pi` are valid, the status code is 1 and the 32-byte output data is hash result of `Alpha`; when any of them is invalid, the status code is 0 and the output data are all zeros.

Example usage in solidity:

```solidity
	function verify(uint alpha, bytes calldata pk, bytes calldata pi, bytes calldata beta) external returns (bool) {
		require(pk.length == 33, 'pk.length != 33');
		(bool ok, bytes memory retData) = address(0x2713).call(abi.encodePacked(alpha, pk, pi));
		return ok && keccak256(retData) == keccak256(beta);
	}
```

## 6. License

The content is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/).


# SEP18: Blockchain cheques on smartBCH

* [SEP-18: Blockchain cheques on smartBCH](/smartbch/smartbch-evolution-proposals-seps/sep-18#blockchain-cheques-on-smartbch)
  * [1. Summary](/smartbch/smartbch-evolution-proposals-seps/sep-18#1--summary)
  * [2. Abstract](/smartbch/smartbch-evolution-proposals-seps/sep-18#2--abstract)
  * [3. Motivation](/smartbch/smartbch-evolution-proposals-seps/sep-18#3--motivation)
  * [4. Status](/smartbch/smartbch-evolution-proposals-seps/sep-18#4--status)
  * [5. Specification](/smartbch/smartbch-evolution-proposals-seps/sep-18#5--specification)
    * [5.1 Blockchain cheques](/smartbch/smartbch-evolution-proposals-seps/sep-18#51-blockchain-cheques)
      * [5.1.1 Methods](/smartbch/smartbch-evolution-proposals-seps/sep-18#511-methods)
        * [5.1.1.1 encryptionPubkeys](/smartbch/smartbch-evolution-proposals-seps/sep-18#5111-encryptionpubkeys)
        * [5.1.1.2 setEncryptionPubkey](/smartbch/smartbch-evolution-proposals-seps/sep-18#5112-setencryptionpubkey)
        * [5.1.1.3 unsetEncryptionPubkey](/smartbch/smartbch-evolution-proposals-seps/sep-18#5113-unsetencryptionpubkey)
        * [5.1.1.4 writeCheque](/smartbch/smartbch-evolution-proposals-seps/sep-18#5114-writecheque)
        * [5.1.1.5 revokeCheque](/smartbch/smartbch-evolution-proposals-seps/sep-18#5115-revokecheque)
        * [5.1.1.6 acceptCheque](/smartbch/smartbch-evolution-proposals-seps/sep-18#5116-acceptcheque)
        * [5.1.1.7 refuseCheque](/smartbch/smartbch-evolution-proposals-seps/sep-18#5117-refusecheque)
      * [5.1.2 Events](/smartbch/smartbch-evolution-proposals-seps/sep-18#512-events)
        * [5.1.2.1 SetEncryptionPubkey](/smartbch/smartbch-evolution-proposals-seps/sep-18#5121-setencryptionpubkey)
        * [5.1.2.2 UnsetEncryptionPubkey](/smartbch/smartbch-evolution-proposals-seps/sep-18#5122-unsetencryptionpubkey)
        * [5.1.2.3 NewCheque](/smartbch/smartbch-evolution-proposals-seps/sep-18#5123-newcheque)
        * [5.1.2.4 RevokeCheque](/smartbch/smartbch-evolution-proposals-seps/sep-18#5124-revokecheque)
        * [5.1.2.5 AcceptCheque](/smartbch/smartbch-evolution-proposals-seps/sep-18#5125-acceptcheque)
        * [5.1.2.6 RefuseCheque](/smartbch/smartbch-evolution-proposals-seps/sep-18#5126-refusecheque)
  * [6. License](/smartbch/smartbch-evolution-proposals-seps/sep-18#6-license)

## 1.  Summary

This SEP proposes an interface standard for sending and receiving blockchain cheques on smartBCH.

## 2.  Abstract

The following standard defines the implementation of APIs for blockchain cheque smart contracts. Such contracts hold the tokens the sender transfers and the receiver can choose to accept them or return them back to the sender.

## 3.  Motivation

In the physical world, you can write paper cheques to some payees. Cheques have richer information and features than normal cash payments. They can carry memos to explain the reason. They have deadlines to enforce the payees to accept them before a given date. The payees can choose to accept the funds or reject them by destroying the paper cheque.

In some scenarios, we would like to mimic paper cheques using smart contracts. Besides, blockchain cheques can provide more security by requiring passphrase and more privacy by encrypting memos.

## 4.  Status

This SEP is under draft.

## 5.  Specification

### 5.1 Blockchain cheques

**NOTES**:

* The following specifications use syntax from Solidity **0.8.6** (or above)
* All the listed functions and events MUST be implemented.

#### 5.1.1 Methods

**5.1.1.1 encryptionPubkeys**

```
function encryptionPubkeys(address receiver) external view returns (uint);
```

Blockchain cheques can carry memos. To preserve privacy, all the memos must be encrypted with the receiver's public key for encryption. If a receiver does not book her public key for encryption in the contract, then nobody can send cheques with non-zero-length memos to her.

Given a reciever's address, the function `encryptionPubkeys` returns the corresponding 32-byte public key for encryption. It returns zero if the receiver does not book a public key.

**5.1.1.2 setEncryptionPubkey**

```
function setEncryptionPubkey(uint pubkey, address referee) external;
```

A user uses `setEncryptionPubkey` to set `pubkey` as her public key for encryption. The argument `referee` is the address of the account who suggest this user to call `setEncryptionPubkey`. It can be set to zero if there is no referee at all.

**5.1.1.3 unsetEncryptionPubkey**

```
function unsetEncryptionPubkey() external;
```

A user uses `unsetEncryptionPubkey` to cancel her public key for encryption. After that, this contract no longer allows sending any cheques with non-zero-length memos to her.

**5.1.1.4 writeCheque**

```
function writeCheque(address payee,
            address coinType,
            uint96 amount,
            uint64 deadline,
            uint passphraseOrHashtag,
            bytes calldata memo) external payable;
function writeCheques(address[] calldata payeeList,
            address coinType,
            uint96 amount,
            uint64 deadline,
            uint[] calldata passphraseHashList,
            bytes[] calldata memoList) external payable;
```

The function `writeCheque` is used to write a cheque to the `payee`. The fund contained in the cheque must be an SEP20 token, whose address is `coinType`. The fund quantity is specified by `amount`. The `payee` must accept this cheque before the time `deadline`, which is UNIX timestamp, or this cheque will get expired.

A cheque can has a passphrase or a hash tag, according to the `passphraseOrHashtag` argument: 1. If this argument is zero, then this cheque has no passphrase nor hash tag. 2. Otherwise, if the most significant byte of this argument is 35 (the ascii code of "#"), then this cheque has a hash tag. Hash tag is usually a human-readable short string. 3. Otherwise, if the most significant byte of this argument is not 35, then the other 31 bytes of `passphraseOrHashtag` is a hash calculated from a passphrase. The passphrase can be transferred off-chain to the receiver, through e-mail, IM or other tools. The `memo` can also hint the receiver about what the passphrase is. To accept the cheque and get the fund in it, the receiver must provide correct passphrase, whose low 31 bytes of `keccak256` hash must be equal to the low 31 bytes of `passphraseOrHashtag`. The exact value of the highest byte is not taken into consideration.

A cheque can has a memo, which is always encrypted with the receiver's public key for encryption. If a receiver does not book her public key for encryption in the contract, the contract must refuse anyone to send cheques with non-zero-length memos to her.

The function `writeCheques` is a batched version of `writeCheque`. It can write several cheques to different receivers at one time. The `deadline` and the funds' `coinType` and `amount` for the cheques must be the same. The memos and passphrases (or hashtags) for different recievers, can be different.

For each sent cheque, the contract must assign a unique 256-bit ID to it, which will be used to refer to this cheque in the subsequent operations.

**5.1.1.5 revokeCheque**

```
function revokeCheque(uint id) public;
function revokeCheques(uint[] calldata idList) external;
```

The sender who wrote a cheque can revoke it by calling `revokeCheque` with the cheque's `id`, after it is expired, i.e., passes its deadline. Thus she can take back the fund inside the cheque.

The function `revokeCheques` is a batched version of `revokeCheque`. It revokes multiple expired cheques at a time.

**5.1.1.6 acceptCheque**

```
function acceptCheque(uint id, bytes calldata passphrase) external;
function acceptCheques(uint[] calldata idList) external;
```

The receiver can accept a cheque by providing a passphrase, before it is expired. If the cheque has a passphrase, then passphrase provided by the receiver will be hashed and checked against the `passphraseOrHashtag` field. If the passphrase is incorrent, the receiver cannot get the fund.

The function `acceptCheques` is a batched version of `acceptCheque`, which does not have a `passphrase` argument. All the specified cheques must have no passphrase.

**5.1.1.7 refuseCheque**

```
function refuseCheque(uint id) external;
function refuseCheques(uint[] calldata idList) external;
```

The receiver can refuse a cheque anytime before it is expired. The fund inside the refused cheque will be immediately returned back to the sender.

The function `refuseCheques` is a batched version of `refuseCheque`.

#### 5.1.2 Events

**5.1.2.1 SetEncryptionPubkey**

```
event SetEncryptionPubkey(address indexed payee, address referee, uint key);
```

* **MUST** trigger when a user sets her public key for encryption.

**5.1.2.2 UnsetEncryptionPubkey**

```
event UnsetEncryptionPubkey(address indexed payee);
```

* **MUST** trigger when a user unsets her public key for encryption.

**5.1.2.3 NewCheque**

```
event NewCheque(address indexed payee, uint indexed id, address indexed drawer,
        uint coinTypeAndAmount, uint startAndEndTime, uint passphraseOrHashtag, bytes memo);
```

* **MUST** trigger when a new cheque is successfully generated. `payee` is the account who can accept this cheque, `id` is assigned by the contract to uniquely identify this cheque, and `drawer` is the account who writes this cheque. The `passphraseOrHashtag` and `memo` have the same value as the arguments for calling `writeCheque`. The high 160 bits of `coinTypeAndAmount` is the fund's SEP20 address and the low 96 bits is the amount. The bits 127-64 of `startAndEndTime` is the time when this cheque is generated and bits 63-0 of `startAndEndTime` is the deadline.

**5.1.2.4 RevokeCheque**

```
event RevokeCheque(address indexed payee, uint indexed id, address indexed drawer);
```

* **MUST** trigger when an expired cheque is revoked. `payee` is the account who did not accept this cheque, `id` was assigned by the contract to uniquely identify this cheque, and `drawer` is the account who wrote this cheque.&#x20;

**5.1.2.5 AcceptCheque**

```
event AcceptCheque(address indexed payee, uint indexed id, address indexed drawer);
```

* **MUST** trigger when a cheque is accepted. `payee` is the account who accepts this cheque, `id` was assigned by the contract to uniquely identify this cheque, and `drawer` is the account who wrote this cheque.&#x20;

**5.1.2.6 RefuseCheque**

```
event RefuseCheque(address indexed payee, uint indexed id, address indexed drawer);
```

* **MUST** trigger when a cheque is refused. `payee` is the account who refuses this cheque, `id` was assigned by the contract to uniquely identify this cheque, and `drawer` is the account who wrote this cheque.&#x20;

## 6. License

The content is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/).


# SEP20: Tokens on smartBCH

* [SEP-20: Tokens on smartBCH](/smartbch/smartbch-evolution-proposals-seps/sep-20#sep20-tokens-on-smartbch)
  * [1. Summary](/smartbch/smartbch-evolution-proposals-seps/sep-20#1--summary)
  * [2. Abstract](/smartbch/smartbch-evolution-proposals-seps/sep-20#2--abstract)
  * [3. Motivation](/smartbch/smartbch-evolution-proposals-seps/sep-20#3--motivation)
  * [4. Status](/smartbch/smartbch-evolution-proposals-seps/sep-20#4--status)
  * [5. Specification](/smartbch/smartbch-evolution-proposals-seps/sep-20#5--specification)
    * [5.1 Token](/smartbch/smartbch-evolution-proposals-seps/sep-20#51-token)
      * [5.1.1 Methods](/smartbch/smartbch-evolution-proposals-seps/sep-20#511-methods)
        * [5.1.1.1 name](/smartbch/smartbch-evolution-proposals-seps/sep-20#5111-name)
        * [5.1.1.2 symbol](/smartbch/smartbch-evolution-proposals-seps/sep-20#5112-symbol)
        * [5.1.1.3 decimals](/smartbch/smartbch-evolution-proposals-seps/sep-20#5113-decimals)
        * [5.1.1.4 totalSupply](/smartbch/smartbch-evolution-proposals-seps/sep-20#5114-totalsupply)
        * [5.1.1.5 balanceOf](/smartbch/smartbch-evolution-proposals-seps/sep-20#5115-balanceof)
        * [5.1.1.6 owner](/smartbch/smartbch-evolution-proposals-seps/sep-20#5116-owner)
        * [5.1.1.7 transfer](/smartbch/smartbch-evolution-proposals-seps/sep-20#5117-transfer)
        * [5.1.1.8 transferFrom](/smartbch/smartbch-evolution-proposals-seps/sep-20#5118-transferfrom)
        * [5.1.1.9 approve](/smartbch/smartbch-evolution-proposals-seps/sep-20#5119-approve)
        * [5.1.1.10 allowance](/smartbch/smartbch-evolution-proposals-seps/sep-20#51110-allowance)
        * [5.1.1.11 increaseAllowance](/smartbch/smartbch-evolution-proposals-seps/sep-20#51111-increaseAllowance)
        * [5.1.1.12 decreaseAllowance](/smartbch/smartbch-evolution-proposals-seps/sep-20#51112-decreaseAllowance)
      * [5.1.2 Events](/smartbch/smartbch-evolution-proposals-seps/sep-20#512-events)
        * [5.1.2.1 Transfer](/smartbch/smartbch-evolution-proposals-seps/sep-20#5121-transfer)
        * [5.1.2.2 Approval](/smartbch/smartbch-evolution-proposals-seps/sep-20#5122-approval)
  * [6. License](/smartbch/smartbch-evolution-proposals-seps/sep-20#6-license)

## 1.  Summary

This SEP proposes an interface standard to create token contracts on smartBCH.

## 2.  Abstract

The following standard defines the implementation of APIs for token smart contracts. It is proposed by deriving the ERC20 protocol of Ethereum and provides the basic functionality to transfer tokens, allow tokens to be approved so they can be spent by another on-chain third party.

## 3.  Motivation

A standard interface allows any tokens on smartBCH to be used by other applications: from wallets to decentralized exchanges in a consistent way. Besides, this standard interface also extends [ERC20](https://eips.ethereum.org/EIPS/eip-20) to facilitate cross chain transfer.

## 4.  Status

This SEP is under draft.

## 5.  Specification

### 5.1 Token

**NOTES**:

* The following specifications use syntax from Solidity **0.5.16** (or above)
* Callers MUST handle false from returns (bool success). Callers MUST NOT assume that false is never returned!

#### 5.1.1 Methods

**5.1.1.1 name**

```
function name() external view returns (string)
```

* Returns the name of the token - e.g. "MyToken".
* **OPTIONAL** - This method can be used to improve usability, but interfaces and other contracts MUST NOT expect these values to be present.

**5.1.1.2 symbol**

```
function symbol() external view returns (string)
```

* Returns the symbol of the token. E.g. “HIX”.
* This method can be used to improve usability
* **NOTE** - This method is optional in EIP20. In SEP20, this is a required method.

**5.1.1.3 decimals**

```
function decimals() external view returns (uint8)
```

* Returns the number of decimals the token uses - e.g. 8, means to divide the token amount by 100000000 to get its user representation.
* This method can be used to improve usability
* **NOTE** - This method is optional in EIP20. In SEP20, this is a required method.

**5.1.1.4 totalSupply**

```
function totalSupply() external view returns (uint256)
```

* Returns the total token supply.

**5.1.1.5 balanceOf**

```
function balanceOf(address _owner) external view returns (uint256 balance)
```

* Returns the account balance of another account with address `_owner`.

**5.1.1.6 owner**

```
function owner() external view returns (address);
```

* Returns the sep20 token owner which is necessary for binding with sep20 token.
* **OPTIONAL** - This method can be used to improve usability, but interfaces and other contracts MUST NOT expect these values to be present.

**5.1.1.7 transfer**

```
function transfer(address _to, uint256 _value) external returns (bool success)
```

* Transfers `_value` amount of tokens to address `_to`, and MUST fire the Transfer event. The function SHOULD throw if the message caller’s account balance does not have enough tokens to spend.
* **NOTE** - Transfers of 0 values MUST be treated as normal transfers and fire the Transfer event.
* **NOTE** - If there are some permission-control mechanism in the smart contract (such as blacklist), transfers of 0 values MUST be treated as normal transfers and undergo the same permission checks.

**5.1.1.8 transferFrom**

```
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success)
```

* Transfers `_value` amount of tokens from address `_from` to address `_to`, and MUST fire the Transfer event.
* The transferFrom method is used for a withdraw workflow, allowing contracts to transfer tokens on your behalf. This can be used for example to allow a contract to transfer tokens on your behalf and/or to charge fees in sub-currencies. The function SHOULD throw unless the `_from` account has deliberately authorized the sender of the message via some mechanism.
* **NOTE** - Transfers of 0 values MUST be treated as normal transfers and fire the Transfer event.

**5.1.1.9 approve**

```
function approve(address _spender, uint256 _value) external returns (bool success)
```

* Allows `_spender` to withdraw from your account multiple times, up to the `_value` amount. If this function is called again it overwrites the current allowance with `_value`.
* **NOTE** - To prevent attack vectors like the one described here and discussed here, clients SHOULD make sure to create user interfaces in such a way that they set the allowance first to 0 before setting it to another value for the same spender. THOUGH The contract itself shouldn’t enforce it, to allow backwards compatibility with contracts deployed before

**5.1.1.10 allowance**

```
  function allowance(address _owner, address _spender) external view returns (uint256 remaining)
```

* Returns the amount which `_spender` is still allowed to withdraw from `_owner`.

**5.1.1.11 increaseAllowance**

```
  function increaseAllowance(address _spender, uint256 _delta) external returns (bool success)
```

* Increases the amount which `_spender` is still allowed to withdraw from you.
* **OPTIONAL** - This method can be used to prevent attack vectors, but interfaces and other contracts MUST NOT expect these values to be present.

**5.1.1.12 decreaseAllowance**

```
    function decreaseAllowance(address _spender, uint256 _delta) external returns (bool success)
```

* Decreases the amount which `_spender` is still allowed to withdraw from you.
* **OPTIONAL** - This method can be used to prevent attack vectors, but interfaces and other contracts MUST NOT expect these values to be present.

#### 5.1.2 Events

**5.1.2.1 Transfer**

```
event Transfer(address indexed _from, address indexed _to, uint256 _value)
```

* **MUST** trigger when tokens are transferred, including zero value transfers.
* A token contract which creates new tokens SHOULD trigger a Transfer event with the `_from` address set to 0x0 when tokens are created.

**5.1.2.2 Approval**

```
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
```

**MUST** trigger on any successful call to `approve(address _spender, uint256 _value)`, `increaseAllowance(address _spender, uint256 _delta)` or `decreaseAllowance(address _spender, uint256 _delta)`. **OPTIONAL** may trigger on any successful call to `transferFrom(address _from, address _to, uint256 _value)` which changes allowance, but it is not required.

## 6. License

The content is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/).


# SEP206: Manipulate Native Token as a SEP20 Token

* [SEP-206: Manipulate Native Token as a SEP20 Token](#sep206-manipulate-native-token-as-a-sep20-token)
  * [1. Summary](#1--summary)
  * [2. Abstract](#2--abstract)
  * [3. Motivation](#3--motivation)
  * [4. Status](#4--status)
  * [5. Specification](#5--specification)
    * [5.1 Token](#51-token)
      * [5.1.1 Methods](#511-methods)
        * [5.1.1.1 name](#5111-name)
        * [5.1.1.2 symbol](#5112-symbol)
        * [5.1.1.3 decimals](#5113-decimals)
        * [5.1.1.4 totalSupply](#5114-totalsupply)
        * [5.1.1.5 balanceOf](#5115-balanceof)
        * [5.1.1.6 transfer](#5116-transfer)
        * [5.1.1.7 transferFrom](#5117-transferfrom)
        * [5.1.1.8 approve](#5118-approve)
        * [5.1.1.9 allowance](#5119-allowance)
        * [5.1.1.10 increaseAllowance](#51110-increaseAllowance)
        * [5.1.1.11 decreaseAllowance](#51111-decreaseAllowance)
      * [5.1.2 Events](#512-events)
        * [5.1.2.1 Transfer](#5121-transfer)
        * [5.1.2.2 Approval](#5122-approval)
      * [5.1.3 Gas Cost](#513-gas-cost)
  * [6. License](#6-license)

## 1. Summary

This SEP proposes a method to manipulate the native token, i.e., BCH, through a pseudo smart contract with SEP20 interface.

## 2. Abstract

On Ethereum, the developers of DApp have always a pain: ETH is not an ERC20 token. And the methods to manipulate ETH and ERC20 tokens are totally different. There are two ways to alleviate this problem:

1. Wrap ETH to make it an ERC20 token: [WETH](https://weth.io).
2. Write two sets of logic in smart contracts to support ETH and ERC20 seperately.

These methods are neither perfect.

On smartBCH, a psuedo smart contract can help you manipulate BCH directly. This smart contract is psuedo because it is not implemented by EVM bytecode. Instead, it is supported natively in the full client, smartbchd. So it can do a thing that no other smart contracts can do: moving BCH. It has a predefined address: 10001, like the precompiled contracts.

This pseudo contract has a SEP20 interface, it can be called as if it is SEP20 smart contract.

## 3. Motivation

This proposal specifies the behavior of functions in this psuedo smart contract, such that developers can use it correctly.

## 4. Status

This SEP has been implemented since genesis.

## 5. Specification

### 5.1 Token

**NOTES**:

* The following specifications use syntax from Solidity **0.5.16** (or above)
* The following methods must be invoked through `call` or `staticall`, `delegatecall` and `callcode` are not allowed.
* The allowance granted by `owner` to `spender` is stored at the slot whose location is calculated as `uint(sha256(abi.encodePacked(uint(owner), uint(spender))`. The size of this slot is not required to be 32-byte long and you can NOT read its value with `eth_getStorageAt`.

#### 5.1.1 Methods

**5.1.1.1 name**

```
function name() external view returns (string)
```

* Returns "BCH".

**5.1.1.2 symbol**

```
function symbol() external view returns (string)
```

* Returns "BCH".

**5.1.1.3 decimals**

```
function decimals() external view returns (uint8)
```

* Returns 18.

**5.1.1.4 totalSupply**

```
function totalSupply() external view returns (uint256)
```

* Returns 2.1E25.
* **NOTE** - Most of the BCH tokens of smartBCH will be locked in a smart contract, which is be controlled by the gateway keepers.

**5.1.1.5 balanceOf**

```
function balanceOf(address _owner) external view returns (uint256 balance)
```

* Returns the BCH balance of another account with address `_owner`.
* Returns the same value as the `eth_getBalance` function in Web3 API.

**5.1.1.6 transfer**

```
function transfer(address _to, uint256 _value) external returns (bool success)
```

* Transfers `_value` amount of BCH to address `_to`, and fire the Transfer event. The function throws if the message caller’s account balance does not have enough tokens to spend.

**5.1.1.7 transferFrom**

```
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success)
```

* Transfers `_value` amount of BCH from address `_from` to address `_to`, and fires the Transfer event.
* The function throws unless the `_from` account has deliberately authorized the sender of the message via allowance control.

**5.1.1.8 approve**

```
function approve(address _spender, uint256 _value) external returns (bool success)
```

* Allows `_spender` to withdraw from your account multiple times, up to the `_value` amount of BCH. If this function is called again it overwrites the current allowance with `_value`.

**5.1.1.9 allowance**

```
  function allowance(address _owner, address _spender) external view returns (uint256 remaining)
```

* Returns the amount which `_spender` is still allowed to withdraw from `_owner`.

**5.1.1.10 increaseAllowance**

```
  function increaseAllowance(address _spender, uint256 _delta) external returns (bool success)
```

* Increases the amount which `_spender` is still allowed to withdraw from you.

**5.1.1.11 decreaseAllowance**

```
    function decreaseAllowance(address _spender, uint256 _delta) external returns (bool success)
```

* Decreases the amount which `_spender` is still allowed to withdraw from you.

#### 5.1.2 Events

**5.1.2.1 Transfer**

```
event Transfer(address indexed _from, address indexed _to, uint256 _value)
```

* It's triggerred when tokens are transferred, including zero value transfers.

**5.1.2.2 Approval**

```
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
```

* It's triggerred on any successful call to `approve(address _spender, uint256 _value)`, `increaseAllowance(address _spender, uint256 _delta)` or `decreaseAllowance(address _spender, uint256 _delta)`.

#### 5.1.3 Gas Cost

Calling these functions costs fixed gas, as is shown below:

* name: 3000
* symbol: 3000
* decimals: 1000
* totalSupply: 1000
* balanceOf: 20000
* transfer: 32000
* transferFrom: 40000
* approve: 25000
* allowance: 20000
* increaseAllowance: 31000
* decreaseAllowance: 31000

## 6. License

The content is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/).


# SEP201: Simple Stochastic Payment

* [SEP-201: Simple Stochastic Payment](#simple-stochastic-payment)
  * [1. Summary](#1--summary)
  * [2. Abstract](#2--abstract)
  * [3. Motivation](#3--motivation)
  * [4. Status](#4--status)
  * [5. Specification](#5--specification)
    * [5.1 payment agent interface](#51-payment-agent-interface)
      * [5.1.1 Methods](#511-methods)
        * [5.1.1.1 pay](#5111-pay)
      * [5.1.2 Prevent Replay Attacks](#512-prevent-replay-attacks)
  * [6. License](#6-license)

## 1. Summary

This SEP proposes a simple interface standard to perform stochastic payment on smartBCH.

## 2. Abstract

Stochastic payment can support transfers of extremely small value.

Suppose Alice provides a kind of service and every time she serves Bob, Bob should pay 0.001 USD to her. Since 0.001 USD is a very small value, the miner fee (or gas fee) on most blockchains are much higher than it. Of course Bob is not willing to pay her 0.001 USD service fee while paying the network 0.1 USD as miner fee.

So, Alice and Bob agreed to gamble on the payment. At each payment, Alice has 0.1% probability to get 1 USD from Bob. If they perform the payment many times, then averagely Bob pays 0.1 USD to Alice in one single time of payment.

Unlike pre-payment or post-payment, stochastic payment is trustless. So it has its unique value in many use cases.

## 3. Motivation

A standard interface allows wallets and service provides interact smoothly.

## 4. Status

This SEP is under draft.

## 5. Specification

### 5.1 Payment Agent Interface

A smart contract acts as the agent for stochastic payment. It's interface is specified here.

**NOTES**:

* The following specifications use syntax from Solidity **0.8.9** (or above)

#### 5.1.1 Methods

**5.1.1.1 pay**

The payer and payee use the classic [commitment scheme](https://en.wikipedia.org/wiki/Commitment_scheme) to gamble on payment.

Before the payer and the payee start the payment. They prepare two 248-bit random number `payerSalt` and `payeeSalt` seperately and then keep them as secrets.

When they agree to start the payment, the payee transfers `payeeSaltHash`(the keccak256 hash of `payeeSalt`) and her address `payeeAddr`, to the payer. And they negotiate to decide the following parameters:

1. `dueTime`: a 64-bit timestamp, after which time this payment cannot take effect on chain
2. `sep20Contract`: the address of the SEP20 token, which is used in this payment
3. `amount` how many coins the payee may possibly get. It must be less than `2**96`.
4. `prob` a 32-bit integer. `prob/(2**32)` is the probability that payee get the `amount` coins

Then the payer queries `payerAllowance`, his allowance of the SEP20 token to the stochastic payment agent contract, before he signs the following parameters using the EIP712 standard:

1. `payerSalt`
2. `payeeSaltHash`
3. `payeeAddr_dueTime64_prob32`: concatenation of `payeeAddr` (bit 255-96), `dueTime64` (bit 95-32) `prob32` (bit 31-0).
4. `payerAllowance`
5. `sep20Contract_amount`: concatenation of `sep20Contract` (bit 255-96), `amount` (bit 95-0).

The signature generated by him contains three parts: 256-bit `r`, 256-bit `s` and 8-bit `v`. All the above parameters and this signature are sent to the payee, who must provide the service to the payer and may call the stochastic agent contract's `pay` function with following arguments:

```
function pay(uint256 payeeSalt_v,
	     uint256 payerSalt,
	     bytes32 payeeSaltHash,
	     uint256 payeeAddr_dueTime64_prob32, 
	     uint256 payerAllowance,
	     uint256 sep20Contract_amount,
	     bytes32 r, bytes32 s) external;
```

The argument `payeeSalt_v` is the concatenation of `payeeSalt` (bit 255-8) and `v` (bit 7-0). The other arguments' meaning has been described above.

The payment agent recovers the payer's address from the signature and then transfer `amount` tokens from payer to payee if and only if the following expression holds:

```
uint32(uint(keccak256(abi.encodePacked(payerSalt+(payeeSalt_v>>8))))) < uint32(payeeAddr_dueTime64_prob32)
```

This boolean expression's value depends on both `payerSalt` and `payeeSalt`, so no single party can control it. And because the payer never knows `payeeSalt`, he does not know the result beforehand. The payee knows every argument and infer the result before her sending transaction to call the agent contract: if the result is "not paying", she never broadcasts the transaction, which is meaningless.

#### 5.1.2 Prevent Replay Attacks

The payment agent must check whether the argument `payerAllowance` exactly equals the payer's current allowance to the agent. If it is not, the payment must fail. Once the payee get paid, the payer's allowance to the agent is deducted. Thus the payee cannot call the agent again with the same argument to get the coins again.

The payer can cancel his allowance to the payment agent at any time by setting the allowance to zero. When he wants to approve allowance to the agent again, the allowance value must be set as `block.number << 192`, where `block.number` is the latest block height. Using this method, the his allowance value to the agent will never have duplicated values, since the maximum amount paid in each time is less than `2**96`.

## 6. License

The content is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/).


# Single Node Private Testnet

This document shows how to start a private testnet of smartBCH with only one node.

We suggest to use ubuntu 20.04.

#### Step 0: build smartbchd

Please follow [this document](https://github.com/smartbch/docs/blob/master/developers-guide/build-smartbchd.md) to build `smartbchd` , the executable of smartBCH's full node client.

#### Step 1: generate some private keys only used for test.

```bash
cd ~/smart_bch/smartbch
./smartbchd gen-test-keys -n 10
7fc6cf51adb430d9220c9f3ed4e992e75b5d1e8e52fe2bc99183cadc141725bc
08c65e04cd27b03d8bb8d19ffadadd82c2dd0935e3f23f313857a2c9629bba43
594d82ba88e52b2e037da8513493074eee5e6a6820d836afee5764fb78830285
433721d2f0e5c90d0a67a91153eaac3aa9db974ba9b4b9a7be219f02c12c015d
ff1f7f7276b877274043a42d17258b79dd4fd32ca17c48a5dc75049c1f931841
bab883ae3c7578be66ba5f1c1798dd52ab84ff9403a62c0b478491264df4a50e
2698171de1409b229fa14b71fa982507b276c7234c34cee8c42ac0713a614a4f
cb7883806fa970ef34b10286b80122b3188b09a24d154d2b81fb30e61c8b99ad
e58d53577a8c30b550db1b461c5aee5c8368946be945819cdfdd77dd990e55cd
fbb4694007aff7a979f46e76f9ec522015ed74702594864bde419a6c4a24f377
```

The output private keys will be used as input for the next step.

A validator needs two private keys: one ed25519 key for consensus engine (tendermint) and one secp256k1 key for operate it using smart contracts. Now we pick the secp256k1 key out from above generated keys. We just choose the first one and show its corresponding address:

```bash
ethereum_private_key_to_address 7fc6cf51adb430d9220c9f3ed4e992e75b5d1e8e52fe2bc99183cadc141725bc
0xd5Fd2C57069d93B6cE3126275a288D21b8aA2E87
```

If you have not installed the `ethereum_private_key_to_address` tool, install it as below:

```bash
sudo apt install npm
npm install -g ethereum-private-key-to-address
```

#### Step 2: initialize the node data using test keys generated above:

```bash
./smartbchd init mynode --chain-id 0x2711 \
  --init-balance=1000000000000000000000000000000 \
  --test-keys="7fc6cf51adb430d9220c9f3ed4e992e75b5d1e8e52fe2bc99183cadc141725bc,\
08c65e04cd27b03d8bb8d19ffadadd82c2dd0935e3f23f313857a2c9629bba43,\
594d82ba88e52b2e037da8513493074eee5e6a6820d836afee5764fb78830285,\
433721d2f0e5c90d0a67a91153eaac3aa9db974ba9b4b9a7be219f02c12c015d,\
ff1f7f7276b877274043a42d17258b79dd4fd32ca17c48a5dc75049c1f931841,\
bab883ae3c7578be66ba5f1c1798dd52ab84ff9403a62c0b478491264df4a50e,\
2698171de1409b229fa14b71fa982507b276c7234c34cee8c42ac0713a614a4f,\
cb7883806fa970ef34b10286b80122b3188b09a24d154d2b81fb30e61c8b99ad,\
e58d53577a8c30b550db1b461c5aee5c8368946be945819cdfdd77dd990e55cd,\
fbb4694007aff7a979f46e76f9ec522015ed74702594864bde419a6c4a24f377"
```

After successfully executing the above commands, you can find the initialized data in the `~/.smartbchd` directory. By using the `--home` option for `./smartbchd` command, you can specify another directory. In the `~/.smartbchd` directory, the genesis file specifies that all the EOAs corresponding to the above private keys will have a balance of 1000000000000000000000000000000.

#### Step 3: generate genesis validator consensus key info

Now we generate the ed25519 private key for consensus engine:

```bash
./smartbchd generate-consensus-key-info | tee generate-consensus-key-info.txt
d6569de9567bac00d9946dc72ca71ffe0ff735729eb966e8437d6b6b24fe0ff1
```

The output hex string is consensus pubkey which will be used in `generate-genesis-validator` command, and a file containing the consensus public and private key is generated under the current directory, named `priv_validator_key.json`.

Since now we are just running a single node for test, the key file is not so important. In production, a validator's operator must take good care of this key file `priv_validator_key.json` and back it up safely.

#### Step 4: generate genesis validator info using pubkey generated above

```bash
./smartbchd generate-genesis-validator \
	--validator-address=0xd5Fd2C57069d93B6cE3126275a288D21b8aA2E877 \
	--consensus-pubkey=d6569de9567bac00d9946dc72ca71ffe0ff735729eb966e8437d6b6b24fe0ff1 \
	--voting-power=1 \
	--staking-coin=1000000000000000000000 \
	--introduction="freeman"
7b2241646472657373223a5b3231332c3235332c34342c38372c362c3135372c3134372c3138322c3230362c34392c33382c33392c39302c34302c3134312c33332c3138342c3137302c34362c3133355d2c225075626b6579223a5b3231352c362c3232372c3135392c3232302c37312c39342c36372c3235312c3230352c3139332c3233312c3231352c3232342c3130342c3132342c3232352c37352c36332c3235312c3133352c3139392c3233302c3135372c352c3138372c32362c3234352c32312c3136362c37352c36355d2c22526577617264546f223a5b3231332c3235332c34342c38372c362c3135372c3134372c3138322c3230362c34392c33382c33392c39302c34302c3134312c33332c3138342c3137302c34362c3133355d2c22566f74696e67506f776572223a312c22496e74726f64756374696f6e223a22667265656d616e222c225374616b6564436f696e73223a5b302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c352c3130372c3139392c39342c34352c39392c31362c302c305d2c2249735265746972696e67223a66616c73657d
```

The `validator-address` uses the one we get at step 1, and the `consensus-pubkey` is the one we get at step 3.

The output hex string contains the information of a validator.

#### Step 5: add genesis validator info to genesis.json using hex string generated above

```bash
./smartbchd add-genesis-validator \
7b2241646472657373223a5b3231332c3235332c34342c38372c362c3135372c3134372c3138322c3230362c34392c33382c33392c39302c34302c3134312c33332c3138342c3137302c34362c3133355d2c225075626b6579223a5b3231352c362c3232372c3135392c3232302c37312c39342c36372c3235312c3230352c3139332c3233312c3231352c3232342c3130342c3132342c3232352c37352c36332c3235312c3133352c3139392c3233302c3135372c352c3138372c32362c3234352c32312c3136362c37352c36355d2c22526577617264546f223a5b3231332c3235332c34342c38372c362c3135372c3134372c3138322c3230362c34392c33382c33392c39302c34302c3134312c33332c3138342c3137302c34362c3133355d2c22566f74696e67506f776572223a312c22496e74726f64756374696f6e223a22667265656d616e222c225374616b6564436f696e73223a5b302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c352c3130372c3139392c39342c34352c39392c31362c302c305d2c2249735265746972696e67223a66616c73657d
```

Using the hex string outputted at the last step as the argument, we call `add-genesis-validator`. It adds one validator's information into the genesis file. You can use this command repeatedly to add more validators. Since we only need one validator for single node test, here we just use this command once.

#### Step 6: copy priv\_validator\_key.json generated in Step 3

```bash
cp ./priv_validator_key.json ~/.smartbchd/config/
```

Thus, when this node starts up, it can use the private consensus key.

#### Step 7: start the node:

```bash
ulimit -n 65536
./smartbchd start --unlock="7fc6cf51adb430d9220c9f3ed4e992e75b5d1e8e52fe2bc99183cadc141725bc,\
08c65e04cd27b03d8bb8d19ffadadd82c2dd0935e3f23f313857a2c9629bba43,\
594d82ba88e52b2e037da8513493074eee5e6a6820d836afee5764fb78830285,\
433721d2f0e5c90d0a67a91153eaac3aa9db974ba9b4b9a7be219f02c12c015d,\
ff1f7f7276b877274043a42d17258b79dd4fd32ca17c48a5dc75049c1f931841,\
bab883ae3c7578be66ba5f1c1798dd52ab84ff9403a62c0b478491264df4a50e,\
2698171de1409b229fa14b71fa982507b276c7234c34cee8c42ac0713a614a4f,\
cb7883806fa970ef34b10286b80122b3188b09a24d154d2b81fb30e61c8b99ad,\
e58d53577a8c30b550db1b461c5aee5c8368946be945819cdfdd77dd990e55cd,\
fbb4694007aff7a979f46e76f9ec522015ed74702594864bde419a6c4a24f377"
```

You can also ignore the `unlock` argument to unlock no accounts.

This command starts the node which provides JSON-RPC service at localhost:8584. You can use the `--http.addr` option to select another port other than localhost:8584. We unlocked accounts created at genesis, which can be shown using the following command:

You can also use `--mainnet-url` option to specify a bitcoincashnode's RPC endpoint, and use `--home` option to specifiy another data directory other than \~/.smartbchd .

```bash
# Run this command in another terminal:
curl -X POST --data '{"jsonrpc":"2.0", "method":"eth_accounts", "params":[],"id":1}' \
    -H "Content-Type: application/json" http://localhost:8545 | jq
```

And you can see something like:

```javascript
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x876367b14fe2c725ed4bfc4ace406ea53db58d0f",
    "0x8c1fe0ad5e59d72ffd064ff80e0c605530af8806",
    "0xa321e9ca672fb04b3c57160f93a40b70fb3f1d6b",
    "0xa6f8d15b18b2b93cbf7fae192184ccd9e03bfaf4",
    "0xb77f11af5206fdfd87011744ea1c0b3bf77ca4ec",
    "0xc38a47a2481bc692c2203e7e7e5e73c474bea43c",
    "0xd5fd2c57069d93b6ce3126275a288d21b8aa2e87",
    "0xdc7c3b6c76eed26bf224a9f1a300b79ce8bc68b2",
    "0xf995503a428d2deaeb53075dc0476affeee95f05",
    "0xfb2c39aafd37c6d17e16b73cc8601f77ed5586b9"
  ]
}
```

You can find the documents for RPC [here](/smartbch/developers-guide/jsonrpc).


# Multi-Node Testnet

This document shows how to start a testnet of smartBCH with multiple nodes.

We suggest to use ubuntu 20.04.

Among these nodes, just pick one to generate the genesis file. And all the other nodes do not generate the genesis file, instead, they use the generated genesis file as is.

### 1. On the nodes which do not generate the genesis file

#### Step 0: build smartbchd

Please follow [this document](https://github.com/smartbch/docs/blob/master/developers-guide/build-smartbchd.md) to build `smartbchd` , the executable of smartBCH's full node client.

#### Step 1: generate the private keys to operate one validator

```bash
cd ~/smart_bch/smartbch
./smartbchd gen-test-keys -n 1 --show-address | tee gen-test-keys.txt
2915b09298d0362df490fe3969b10aece94cd3460fb1ba29184cba31516a9b5f 0xF0c6969C2a554ddae639ba1Aa1d2fA11382CAb2B
```

The above command generates one private key. And the corresponding EOA address is `0xF0c6969C2a554ddae639ba1Aa1d2fA11382CAb2B`.

#### Step 2: generate genesis validator consensus key info

Now we generate the ed25519 private key for consensus engine:

```bash
./smartbchd generate-consensus-key-info |tee generate-consensus-key-info.txt
a07871d10858179c1bb3c1f0d7bab31103135b76f96b6bd1f06a5bc0d350f862
```

The output hex string is consensus pubkey which will be used in `generate-genesis-validator` command, and a file containing the consensus public and private key is generated under the current directory, named `priv_validator_key.json`.

#### Step 3: generate genesis validator info using pubkey generated above

```bash
./smartbchd generate-genesis-validator \
	--validator-address=0xF0c6969C2a554ddae639ba1Aa1d2fA11382CAb2B \
	--consensus-pubkey=a07871d10858179c1bb3c1f0d7bab31103135b76f96b6bd1f06a5bc0d350f862 \
	--voting-power=1 \
	--staking-coin=0 \
	--introduction="happyman"
7b2241646472657373223a5b3136362c3234382c3230392c39312c32342c3137382c3138352c36302c3139312c3132372c3137342c32352c33332c3133322c3230342c3231372c3232342c35392c3235302c3234345d2c225075626b6579223a5b3136302c3132302c3131332c3230392c382c38382c32332c3135362c32372c3137392c3139332c3234302c3231352c3138362c3137392c31372c332c31392c39312c3131382c3234392c3130372c3130372c3230392c3234302c3130362c39312c3139322c3231312c38302c3234382c39385d2c22526577617264546f223a5b3136362c3234382c3230392c39312c32342c3137382c3138352c36302c3139312c3132372c3137342c32352c33332c3133322c3230342c3231372c3232342c35392c3235302c3234345d2c22566f74696e67506f776572223a312c22496e74726f64756374696f6e223a2268617070796d616e222c225374616b6564436f696e73223a5b302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c305d2c2249735265746972696e67223a66616c73657d
```

The `validator-address` is the one we get at step 1, and the `consensus-pubkey` is the one we get at step 2.

The output hex string contains the information of a validator. Send the this hex string to the node who is genesis-generator.

#### Step 4: wait for the data directory's tarball and unpack it

The genesis-generator will send you a tarball named dot.smartbchd.tgz, which contains the initial content for the data directory.

```bash
cd ~
tar zxvf dot.smartbchd.tgz
rm -rf .smartbchd
./smartbchd init mynode --chain-id 0x2711
cp -rf dot.smartbchd/* .smartbchd/
```

#### Step 5: Copy private key file to data directory and start node

Copy priv\_validator\_key.json generated in Step 2, to get the data directory:

```bash
cp ./priv_validator_key.json ~/.smartbchd/config/
```

Now start the node:

```
ulimit -n 65536
./smartbchd start
```

For the `smartbchd start` command, you can use `--mainnet-url` option to specify a bitcoincashnode's RPC endpoint, and use `--home` option to specifiy another data directory other than \~/.smartbchd .

#### Step 6: activate validator

Before you activate your genesis validator, try to get testnet BCH in your validator address, it needs at least

```
1000000000000000000000 bch
```

You can ask the genesis-generator to send you some testnet BCH. And you can check your balance with below command (Replace `your_validator_address` with your genesis validator address):

```
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["your_validator_address","latest"],"id":1}' -H "Content-Type: application/json" http://localhost:8545
```

After you have enough bch, you can run the following command:

```
./smartbchd staking \
--validator-key=07427a59913df1ae8af709f60f536ddba122b0afa8908291471ca58c603a7447 \
--staking-coin=2000000000000000000000000 \
--nonce=0 \
--chain-id=0x2711
```

Note: replace the content after `--validator-key` with your validator private key, and repace the content after `--staking-coin` with `1000000000000000000000` or even more you have.

⚠️Keep your private key safe, and execute this command on a secure, offline machine

Then broadcast the transaction (replace `--your_tx_data` with what hex string get above):

```
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["you_tx_data"],"id":1}' -H "Content-Type: application/json" http://localhost:8545
```

Now, you had send an `editValidator` transaction to staking contract. Check this transaction's receipt (replace `your_tx_hash` with what the hex string you get above):

```
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["your_tx_hash"],"id":1}' -H "Content-Type: application/json" http://localhost:8545
```

If the `status` is `0x1`, congratulations, your genesis validator is activated now.

### 2. On the node which generates the genesis file

#### Step 0: Prepare

Just finish the steps 0-5 as [running a single-node testnet](/smartbch/archives/runsinglenode).

#### Step 1: add genesis validator info to genesis.json using hex strings sent by other nodes

Using `./smartbchd add-genesis-validator` multiple times, one time with one hex string sent by one node. Finally you'll include all the validators' information in the genesis.json file.

Then, make a copy of the `~/.smartbchd` directory, excluding the `node_key.json` file.

```bash
cp -r ~/.smartbchd ~/dot.smartbchd
rm ~/dot.smartbchd/config/node_key.json
```

#### Step 2: start the node

Run the step 6 and 7 as [running a single-node testnet](/smartbch/archives/runsinglenode).

#### Step 4: collect seeds information

Collect the p2p seeds information and modify the `~/dot.smartbchd/config/config.toml` file.

####

#### Step 5: send information to all the other nodes

Make a tarball:

```bash
cd ~
tar czvf dot.smartbchd.tgz dot.smartbchd
```

Then send this dot.smartbchd.tgz file to all the other nodes.

### 3. Join in as a validator after genesis

You can also join in an already-running smartBCH chain as a new validator.

#### Step 0: create new validator

Follow the step 0,1,2 described in the above section 1, to get the validator account key and the consensus key. Then, you can use these key information to build command below:

```
./smartbchd staking \
--validator-key=fceb6fbf700ae1faaf482fbaf7c3dfd2c8635956ed23a3eb1178e5d71ac34dbc \
--staking-coin=1000000000000000000000000 \
--consensus-pubkey=d4849694a7105200464dfc1160c95ed26664b556c3e468b03312ed9ebd937eb4 \
--type=create \
--nonce=0 \
--chain-id=0x2711
```

This command will output a hex string to be used in the next step.

#### Step 1: send transaction to register as a validator

Make sure you have enough BCH in you validator account.

Then broadcast the transaction (replace `your_tx_data` with what hex string get above):

```
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["you_tx_data"],"id":1}' -H "Content-Type: application/json" http://localhost:8545
```

OK, now you had send a `createValidator` transaction to the staking contract. Check this transaction's receipt (replace `your_tx_hash` with what the hex string you get in above command):

```
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["your_tx_hash"],"id":1}' -H "Content-Type: application/json" http://localhost:8545
```

If the `status` is `0x1`, congratulations, your validator is created now, but it has no voting power now.

#### Step 2: voting in the BCH mainnet

Someone must vote for your validator to make it active in a future epoch. If you are using [a fake BCH node](https://github.com/smartbch/testkit/tree/main/bchnode), the voting for new validator can be started using the following command:

```
./bchnode/scripts pubkey.sh "you_consenesus_pubkey"-"you_voting_power"-add
```

Like this: `./pubkey.sh d4849694a7105200464dfc1160c95ed26664b556c3e468b03312ed9ebd937eb4-1-add`

If you are using a real BCH node, please use **`getblocktemplate`** to specify the coinbase transaction for voting.

You can also starting voting before registering the validator, which can make sure then it is registered, it gets voting power as soon as possible.

### 4. Adjust minGasPrice

You can adjust minmum gas price that tx must pay for its gas in smartBCH chain, but only an active validator and its rewardTo address has permission to do this.

#### Step 0: generate minGasPrice adjust signed rawTx

Follow the step 0,1,2 described in the above section 1, to get the validator account key and the consensus key. Then, you can use these key information to build increase minGasPrice command below:

```
./smartbchd staking \
--validator-key=fceb6fbf700ae1faaf482fbaf7c3dfd2c8635956ed23a3eb1178e5d71ac34dbc \
--type=increase \
--nonce=0 \
--chain-id=0x2711
```

or decrease minGasPrice command below:

```
./smartbchd staking \
--validator-key=fceb6fbf700ae1faaf482fbaf7c3dfd2c8635956ed23a3eb1178e5d71ac34dbc \
--type=decrease \
--nonce=0 \
--chain-id=0x2711
```

These two command will output a hex string to be used in the next step.

#### Step 1: send transaction to adjust minGasPrice

Make sure you have enough BCH in you sender account.

Then broadcast the transaction (replace `your_tx_data` with what hex string get above):

```
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["you_tx_data"],"id":1}' -H "Content-Type: application/json" http://localhost:8545
```

OK, now you had send a `increaseMinGasPrice` transaction to the staking contract. Check this transaction's receipt (replace `your_tx_hash` with what the hex string you get in above command):

```
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["your_tx_hash"],"id":1}' -H "Content-Type: application/json" http://localhost:8545
```

If the `status` is `0x1`, congratulations, your update success.


# Fake RPC Server for Testing

## Dependencies

Please follow the guide for [multi-node testnet](broken://pages/-Mb5hpSce9HHUCYcyAPm). And do add the `--mainnet-url` option to specifiy a bitcoincashnode's RPC endpoint, which can be a real one or a fake one, just as following:

```
./smartbchd start --mainnet-url=http://node-ip-address:port-number
```

## Running a Fake RPC Server for Testing

The `bchnode` tool mimics a real bitcoincashnode's RPC behavior. You can use it with the following steps:

### Start the bchnode RPC Server

```
Git clone https://github.com/smartbch/testkit.git
cd bchnode
go run main.go &
```

### Add a New Validator's public key and voting power

The format is `pubkey`-`votingPower`-`action`, where the action can be "add", "edit" or "retire".

```
cd scripts ;# there are some utility scripts in the directory testkit/bchnode/scripts
./pubkey.sh eeed4fae3da010e393efed2aacd271971fd2383fc68109a475d6c9ef65435d52-9-add
```

The `bchnode` produces blocks with fixed interval (default is 3 seconds) to vote for the validators.

### Adjust block interval

To change the block interval to 10 seconds:

```
./interval.sh 10
```

### Simulate a Block Reorg

```
./reorg.sh
```

The `bchnode` will simulate a fork at the height which is 8 blocks less than current height, and re-generate the recent 8 blocks.

## The Suggested Scenarios for Test

1. Configure `bchnode` to follow the voting power and pubkeys specified in genesis.json
2. Keep the current voting power and pubkeys for three epochs.
3. Change the voting power setting of `bchnode`, such that at new epochs, the smartbchd follows the new voting power.
4. Run block reorg at `bchnode`, and smartbchd can work normally.
5. Add new validators in and let `bchnode` vote them to be active.
6. Restart smartbchd and it can also work fine.

## smartBCH parameters for testing with bchnode

```
NumBlocksInEpoch       int64 = 30
NumBlocksToClearMemory int64 = 1000s
WaitingBlockDelayTime  int64 = 2s
SwitchEpochDelayTime   int64 = 10s
MinVotingPercentPerEpoch        = 10 //10 percent in NumBlocksInEpoch, like 2016 / 10 = 201
MinVotingPubKeysPercentPerEpoch = 34 //34 percent in active validators,
```


# Test using MetaMask

In this article, we will show how to test smartBCH single-testing-node using MetaMask. We use Chrome browser as example but Firefox browser should work the same way.

Please note in the following example we assume you are using a [local single-node testnet](broken://pages/-MWsYcX52F9hK3k8er_v). Instead, if you want to use a remote node to provide JSON-RPC, just replace "localhost" with the node's IP address.

## Start smartBCH single-testing-node

Please flow [this doc](broken://pages/-MWsYcX52F9hK3k8er_v) to start smartBCH single testing node. When the testing node is started with default options, it will serve JSON-RPC on localhost:8485. You can use the following cmd to check that the node works well and to see the testing accounts:

```bash
$ curl -X POST --data '{"jsonrpc":"2.0", "method":"eth_accounts", "params":[],"id":1}' \
    -H "Content-Type: application/json" http://localhost:8545 | jq
```

The output looks like this:

```javascript
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x876367b14fe2c725ed4bfc4ace406ea53db58d0f",
    "0x8c1fe0ad5e59d72ffd064ff80e0c605530af8806",
    "0xa321e9ca672fb04b3c57160f93a40b70fb3f1d6b",
    "0xa6f8d15b18b2b93cbf7fae192184ccd9e03bfaf4",
    "0xb77f11af5206fdfd87011744ea1c0b3bf77ca4ec",
    "0xc38a47a2481bc692c2203e7e7e5e73c474bea43c",
    "0xd5fd2c57069d93b6ce3126275a288d21b8aa2e87",
    "0xdc7c3b6c76eed26bf224a9f1a300b79ce8bc68b2",
    "0xf995503a428d2deaeb53075dc0476affeee95f05",
    "0xfb2c39aafd37c6d17e16b73cc8601f77ed5586b9"
  ]
}
```

## Config MetaMask networks

Install MetaMask into your browser, create or import a wallet, and than add a network configuration:

![metamask-select-networks](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F0aad8c78e2612cc07e9b65285b4bded26b51f22f.png?generation=1619421244324157\&alt=media)

If you started smartBCH testing node on localhost:8545 for JSON-RPC, it happens that MetaMask has a preconfigured Network that matched this RPC URL:

![metamask-settings-networks-localhost-8584](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F437716da4af1131c8387e47c8804277c5a434bd1.png?generation=1619421244639653\&alt=media)

But the chain ID may not match, in that case, you can replace 1337 with your smartBCH chain ID (for example, for the smartBCH-T1 testnet, it's 0x2711). And it's better that you change Currency Symbol to BCH. You can also add a new Network configuration like this:

![metamask-settings-networks-new](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2Fc429a7cd3a0b13cffeb373709e4984186383cfa3.png?generation=1619421250251921\&alt=media)

## Create a new account

Create a new account in MetaMask, and let's name it smartBCH\_user1. This newly created account have no BCH (the native token of smartBCH) of cause:

![metamask-new-account](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F065823f0df2ad264571b092ce271dd3babbc78a0.png?generation=1619421249559119\&alt=media)

We can transfer 1 BCH to this account using cmd like this:

```bash
$ curl -X POST --data '{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params":[{
    "from": "0xd5fd2c57069d93b6ce3126275a288d21b8aa2e87",
    "to": "0xc370743331B37d3C6D0Ee798B3918f6561Af2C92",
    "gasPrice": "0x0",
    "value": "0xDE0B6B3A7640000"
  }],
  "id":1}' -H "Content-Type: application/json" http://localhost:8545
```

The `from` address comes from output of `eth_accounts` RPC. The `to` address is copied from MetaMask by clicking the account name. The `value` is amount of BCH to send in HEX, and is amplified by 1018. Just like ETH, 1 BCH on smartBCH chain can be divided into 1018 units. The output looks like this:

```javascript
{"jsonrpc":"2.0","id":1,"result":"0x40f6c7d7e350f295d000520b1a820f4b22535524a7e71b279dff45b2c60ce2c8"}
```

Wait a second, and you can check that your account has received 1 BCH:

![metamask-new-account-1bch](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2Fe0efd8d05fcf76a63f679f86e7b7b972bbcb92f2.png?generation=1619421244872029\&alt=media)

## Transfer BCH using MetaMask

Let's create another new account and name it smartBCH\_user2:

![metamask-new-account2](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F7773870c786b390b8df5b9e97d7f6aae601e1c17.png?generation=1619421244765738\&alt=media)

We can transfer/send to smartBCH\_user2 some BCH from smartBCH\_user1:

![metamask-send-bch](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F51b5ae90a133d4781dd38cf512b80bcf36efe65e.png?generation=1619421251054476\&alt=media)

![metamask-send-confirm](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F22c95943e3ce9b77ddf43d834307abce54bf6a7a.png?generation=1619421250388498\&alt=media)

A few seconds later, the balance of smartBCH\_user1 and smartBCH\_user2 should be updated:

![metamask-send-result1](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2F8b028782910b5640404d7fdd2af7123d41ba050f.png?generation=1619421249688546\&alt=media)

![metamask-send-result2](https://3319495191-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWmt0o30W7ixggmDAgb%2Fsync%2Ffd54b8c260707e7381d00f22de930696d5a1af8f.png?generation=1619421251630975\&alt=media)

Congratulations! You just started smartBCH single-testing node and tested it with the most popular browser wallet MetaMask. If you are new to MetaMask, you can read it's help docs [here](https://metamask.zendesk.com/hc/en-us).


