5. Foundation

Knowledge System

To understand Amaze public chain technology, one needs a certain foundation of knowledge, including blockchain basics, programming languages, smart contracts, principles of cryptography, data structures and algorithms, decentralization and distributed systems, front-end frameworks, and more. Additionally, non-technical skills such as curiosity, determination, and resilience are also required. The Amaze public chain open-source project is developed by a team of software engineers, based on the whitepaper and Amaze Improvement Proposals (AIPs). Developing the Amaze chain involves a wide range of fields, including communication protocols, peer-to-peer networks, databases, cryptography, language interpretation, RPC, and Websockets. This represents a fundamental shift from the current financial system and offers the chance to help reshape the world’s financial system. However, in the world of cryptocurrencies, errors, and security vulnerabilities can have more dire consequences than in traditional projects, necessitating a formal and rigorous development process. Before writing code, it is advisable to possess some minimum recommended skills, such as a reasonable understanding of blockchain, experience with some kind of C-like language, an understanding of data structures and their impact on performance, familiarity with unit testing and debugging experience, etc. Additionally, an understanding of the area being changed and the code it depends on, as well as the code that depends on the changes, is needed. The recommended skill set largely depends on the specific area of contribution, for example, if one wishes to contribute to cryptographic code, a good understanding of security and performance implications is needed. Standards for programming languages like C++, Go, and Rust also need to be followed. Lastly, it is recommended to have basic blockchain knowledge and language foundations before starting to write code, to better understand and construct the code.

Development Practice

Developers should work within their skill range and submit pull requests when they believe a feature or bug fix is ready to be integrated into the main branch.

In development practice, we strongly advocate the "share early, share often" approach. The basic premise of this approach is to announce your plans before starting work and share your changes as a series of small, reviewable commits, so you can share your progress with the community at any time. This approach has several benefits: first, announcing your feature work plan can avoid duplicate efforts; second, it allows for discussion, which can help you implement your goals in a way that is consistent with the existing architecture; third, it minimizes the chances of spending time and energy on changes that may not meet community consensus or existing architecture and therefore may be rejected; finally, incremental development helps ensure you're on the right track with the rest of the community. Sharing your progress early often ensures that your changes are merged into the main branch faster and spend less time catching up with the main codebase.

Testing

In the design of all core packages, achieving complete test coverage is one of the main design goals. As errors in digital currency software can lead to people losing real money, every effort must be made to ensure the code is as accurate and error-free as possible. Thorough testing is crucial to achieve this goal.

Unless your new feature is trivial, it may be rejected unless it also comes with sufficient test coverage, including tests for positive and negative conditions. That is, tests must ensure that your code works correctly when given correct data and incorrectly on wrong data paths.

Programming languages like Go and Rust provide excellent testing frameworks for directly writing test code and checking coverage statistics. Therefore, all new code should be tested to ensure that it behaves correctly when given expected values and can handle errors gracefully. When you fix a bug, it should be accompanied by a test to prove that the bug has been resolved and prevent it from reoccurring in the future.

Code Documentation and Comments

Every function should be commented to indicate its intended purpose and any assumptions. Function comments should always start with the function name, and comments should be complete sentences as they allow for various automated demonstrations. A good rule of thumb is to consider yourself as someone completely unfamiliar with the code and then ask yourself if the comment provides enough information to understand the function's purpose and how to use it.

For exported functions, comments should include details that might be necessary for the function caller to know and/or understand.

Comments should appear in the body of the code but should explain the intent of the code, not just point out the obvious. Due to the development of multi-monitor programming and laptop display resolutions, it is no longer required that each line of comments does not exceed 72 characters, and increased indentation levels are added.

Code Review

All submitted code must undergo code review before being merged into the main branch. This process is performed by project maintainers and often includes other contributors interested in the area.

The time for code review depends on the number of requests to review, the size and complexity of the contribution, whether the guiding principles are followed, and the reviewer's understanding of your submission. For example, if you submit an overall change involving multiple subsystems, obviously it will take longer to review. It may be necessary to split the submission into several smaller, more manageable submissions.

Keeping the above points in mind, most small changes will be reviewed within a day, while larger or more impactful changes may take several days. This is also the benefit of sticking to early sharing, as sharing is often the practice of development.

The main purpose of code review is to ensure that the code follows the development code standards. In addition, other checks are conducted:

• The code is stable and free of security issues;

• The code correctly uses existing APIs and integrates well into the overall architecture;

• The change is considered appropriate by community consensus.

After the code review, if there are no issues, the change will be accepted immediately. If there are any doubts or problems, you will receive feedback and the next steps to take. In some cases, code reviewers or interested contributors may help rewrite your code, but usually, they will only provide feedback so you can make the necessary changes. This process will continue until the code is finally accepted. Once your code is accepted, it will be integrated with the main branch. Typically, it will be rebased and merged quickly as we prefer to keep a clean history of intertwined commits. However, regardless of the specific merging method used, the code will be integrated with the main branch.

The code review checklist includes:

• The submitted code has been annotated according to the code documentation and comments;

• For new code: accompanied by tests, testing both positive and negative (error path) conditions (if applicable);

• For bug fixes: code accompanied by new tests that trigger the bug being fixed to prevent rework;

• Any new logging statements use the appropriate subsystem and logging level;

• The code has been formatted;

• Running tests does not cause any test failures;

• Running static analysis tools does not report any problems;

• Running source code inspection tools to detect code specifications does not report any new issues that did not already exist.

Accounts

In the system, an account is represented by a 20-byte address derived from the last 20 bytes of the hash value of the account's public key. There are two formats for displaying the address in plaintext:

• Base58 encoded format, for example: 14xfJr1DArtYR156XBs28FoYk6sQqirT2s

• Hexadecimal (HEX16) format, for example: 0x9156a7cdab767ffe161ed21a0cb0b688b545b01f

Considering security and ecology, a 32-byte address format will be promoted in 2024.

UTXO Type, Balance Type, Zk Type

Accounts support both UTXO and balance types. In the UTXO type, an account's funds are the total sum of all unspent UTXOs owned by the account.

In the balance system, an account's internal storage includes three parts:

• The latest transaction number (check number) used as a counter to ensure each transaction is processed only once (preventing double-spending)

• The current balance of the account

• Account information, including nickname (domain), contract code (Code), or storage (Data), which is empty by default

Zero-Knowledge (Zk) system addresses are one-time addresses, with senders and receivers creating random obfuscated addresses for each transaction. An account includes a private view key, a private spend key, and a public address.

Sharding

The system is sharded based on account addresses, with each shard's "full node" responsible for storing all transactions, contracts, and states within that shard.

• First level: The system is divided into 256 shards based on the first byte, with the 0th shard being the beacon chain.

• Second level: Based on the first two bytes, the system is divided into 65,536 shards.

• Third level: Based on the first three bytes, the system is divided into 16,777,216 shards.

Thanks to validators using stateless proofs and ZKVMS for verification, they can complete validation tasks in all shards. Thus, sharding in Amaze does not reduce the overall security of the system.

Format: Transaction type || Byte array

The definitions of the above fields are as follows:

• Transaction type: Values from 0 to 0x7f (to be compatible with RLP encoding, the first byte of the transaction is always greater than or equal to 0xc0), representing up to 128 transaction types (including UTXO transactions, balance transactions, token transactions, time-limited transactions, batch transactions, pay-for-others transactions, contracts, data on-chain, etc.).

• Byte array: An arbitrary byte array defined by the transaction type.

In UTXO transaction types, initiating a transaction requires signing the transaction in formats like P2PKH, P2PK, MS (up to 15 keys), P2SH, etc., with a private key. The OP_Return format is used for data on-chain and does not involve a payee.

UTXO transactions contain one or more inputs and one or more outputs. Each input includes a reference to an existing UTXO and a cryptographic signature created by the private key corresponding to the owner's address. Each output contains a new UTXO to be added to the state.

In the balance transaction type, initiating a transaction requires signing a transaction data packet with a private key. The data packet can contain multiple transactions. Each transaction includes the payee's address, transfer amount, optional fee, transaction number (check number), etc.

In Ethereum, the sender's address is derived through signature computation, which requires ECDSA elliptical encryption algorithm verification signature computation and is time-consuming with high transaction volumes. Moreover, since the sender's address is unknown, it's impossible to accurately judge double-spending and whether the payee of one transaction is the sender of another, requiring all transactions to be executed sequentially. Amaze's transaction structure includes the sender's address, facilitating broadcast in associated shards, supporting "out-of-order" concurrent execution, avoiding related transaction conflicts, achieving lock-free concurrent execution, and thus improving transaction efficiency.

Script/Contract Execution

In UTXO, not only can a public key own it, but it can also be owned by complex scripts written in a stack-based programming language. In this mode, to spend such a UTXO, data satisfying the script's requirements must be provided. In fact, the basic public key ownership mechanism is also implemented through a script: the script accepts an elliptical curve signature as input, and verifies the transaction and the address owning the UTXO. If verification is successful, it returns 1; otherwise, it returns 0. Complex scripts can be applied in different scenarios. For example, a script can be created that requires at least two out of three private keys to confirm a transaction (multi-signature), which is very useful for corporate accounts, savings accounts, and certain commercial agents. Scripts can also be used to reward users who solve computational problems. It's even possible to create a script like: "If you can prove you've sent a certain amount of Dogecoin to me, this UTXO is yours." Essentially, the UTXO system allows for the decentralized exchange of different cryptocurrencies.

In transaction types, the contract virtual machine type can be specified as EVM, WASM, MOVE. Also, for Ethereum compatibility, the following method can be used: if the payee's address is empty, it's contract creation; if the payee's address is a contract address, it's a contract call, with the Data field as parameters.

WASM is a lightweight, efficient virtual machine compatible with various hardware, specified by the W3C community team composed of mainstream browser manufacturers. Amaze uses the compact and fast-loading binary format of the WASM virtual machine for debugging, testing, experimenting, optimizing, learning, teaching, or writing smart contract programs, fully leveraging hardware performance to achieve native execution efficiency.

Since contracts are Turing complete, they can be applied in almost all scenarios.

Transaction Pool

After a transaction is signed, it is broadcasted to the nodes of the relevant shard. Once a node receives a broadcasted transaction and successfully verifies the signature, the transaction is added to the transaction pool and continues to be broadcasted within the shard (to nodes that haven't received this transaction yet). For transactions with multiple signatures, they are added to the transaction pool after the signatures are combined.

Consensus Block Creation

Within a shard, block producers are elected through a fast-converging FVRF consensus. The producer processes and executes transactions from the transaction pool, generating verifiable proofs. Validators vote and add a VDF signature after verifying the proof is correct. Within the validation shard's timetable, at least 2/3 of the 128 validators' signatures are required to add the block to the cross-link of the beacon chain.

Ethereum assigns block producers and validators to different shards through the beacon chain, with a dynamic subset of nodes processing shards in block order. In contrast, Amaze processes through cryptographic proof, with block producers and validators set on a global scale, solving shard security issues. Despite the extra work of generating proofs, verification is fast and requires low computational power (calculable by mobile phones). The Amaze chain is primarily used to generate proof blocks, containing verifiable cross-link information provided by the state and transaction content within shards.

Executing Transactions

In the UTXO system, steps to execute a transaction include:

1. For each transaction input:

• If the referenced UTXO is not in the current state (S), return an error.

• If the signature does not match the UTXO owner's signature, return an error.

2. If the total face value of all input UTXOs is less than the total face value of all output UTXOs, return an error.

3. Return the new state S', where all input UTXOs are removed from the new state S, and all output UTXOs are added.

In the balance system, steps to execute a standard transaction include:

1. Check if the balance is sufficient to cover the payment.

2. Deduct the payer's payment amount and increase the payee's receiving amount.

3. Return the new state, which includes updated balances for both parties.

Code Execution

Contract code is written in a low-level, stack-based bytecode language called "virtual machine code." The code includes three types: EVM, WASM, and MOVE. These codes consist of a series of bytes, each representing an operation. Generally, code execution is an infinite loop process, where the program counter (initially zero) continually executes operations, incrementing the program counter by one with each operation, until the code completes, runs out of fuel, detects an error, or encounters STOP or RETURN instructions. The zero-knowledge proof system generates proofs of code execution.

Node Synchronization

Every participant is a full node: Traditional chains have become so large that users must rely on mining farms to run nodes, contradicting the original decentralization concept of blockchain, making the network more susceptible to 51% attacks. However, AmazeChain's mobile node blockchain allows anyone to easily connect and verify transactions peer-to-peer as full nodes, ensuring high resistance to scrutiny and security of the blockchain.

A graceful solution driven by zero-knowledge: AmazeChain does not use the brute-force computation of POW but achieves true large-scale decentralization through advanced cryptographic techniques and recursive zero-knowledge proofs.

Initial Synchronization

In theory, blockchain design is intended to let users take responsibility. When most people can enforce rules through an irreversible public ledger, power lies in the hands of the many, not the few. This decentralized structure allows transactions in a trustless environment.

However, in practice, it is not so. For traditional blockchains like Bitcoin and Ethereum, new participants must check every transaction since the network began to verify its correctness, amounting to hundreds of terabytes of data. Most people cannot afford the computational power to independently verify these massive chains, thus having to trust increasingly powerful mining farms. This means that most people can no longer join the peer-to-peer network, affecting power decentralization, changing network power dynamics, making it more susceptible to censorship.

AmazeChain offers an elegant solution: By using easily verifiable, consistently sized cryptographic proofs, it significantly reduces the amount of data each user needs to download. Participants don't need to verify the entire chain block by block from the start like other chains but use recursive zero-knowledge proofs to verify all blocks, networks, and transactions since the chain's inception in one go. Then, mobile nodes can store small proofs instead of the entire chain, handling transactions and contracts from the current moment. As the proof size remains constant, even with many users and years of accumulated transaction data, it remains accurate and accessible.

Stateless Blockchain

A stateless blockchain supports transactions and blocks (single transactions, a group of transactions, a series of consecutive transactions, single blocks, a group of blocks, a series of consecutive blocks) inputs (such as block headers, sets of transactions within blocks, account information, contract storage information, etc., subsets of state) using polynomial proofs or zero-knowledge proofs. Outputs and proofs generated after ZKVM execution can be verified by other nodes (without needing the full ledger and state).

Compared to typical blockchain systems, a stateless blockchain does not require nodes to store the complete chain state, including all account balances and smart contract states. State proofs can prove transactions are based on valid chain states, which are cryptographic proofs. When verifying transactions, nodes only need to confirm the validity of the proofs, without accessing the complete chain state. Stateless blockchains help alleviate node storage and synchronization burdens, eliminating the need to synchronize the complete chain state, thus speeding up synchronization and lowering barriers to network participation. The advantages of stateless blockchains in balancing storage and computational costs enhance the scalability of blockchain systems.

Distributed Concurrent Execution Verification

This execution and verification can be done concurrently on a single machine with multiple threads, GPU concurrency, across machines, and distributed computing, without any permissioned access threshold, and can even be verified at any moment across time and space.

State Sharding

Blockchain participants only need to possess the genesis block (or re-genesis block or anchor) along with block headers containing timestamps and difficulty verification. The requirements for hardware networking are low, and continuous outputs can also be merged into subsets of state, achieving the effect of state sharding.

Proposers/Validators

Proposers select the highest-bidding valid block header. Only block builders need to process the entire block (which can also be achieved using decentralized oracle protocols for distributed block builders), while all other validators and users can efficiently verify blocks through data availability sampling.

Last updated