Menu

Code review of Algorand

Algorand

Founded by cryptography pioneer, MIT professor and Turing award winner, Silvio Micali, Algorand is aiming to solve the classic “blockchain trilemma” with a platform that delivers decentralization, scalability as well as security in a permissionless network participation scenario.

Algorand’s permissionless, pure proof-of-stake protocol looks to support the scale, open participation, and transaction finality required to build systems for billions of users.
Algorand aspires on being the first blockchain to provide full and immediate transaction finality with no forking. This would remove the uncertainty present in other blockchains, and provides transactional integrity for businesses who will build on the Algorand platform.
Algorand recently opened its TestNet to the public, together with their releases of Java/JavaScript and Golang SDKs.
The TestNet resources are collected on a nicely structured dev website (https://developer.algorand.org) and consists of all that is needed to run standalone nodes and set up private test networks for development purposes.
The source code for the network is not yet publicly released (with the exception of a few installation script files), however InCodeWeTrust has acquired permission to access Algorand’s private repositories for the purpose of this article.

ALGORAND NETWORK PRINCIPLES
Algorand’s new protocol is aiming to be fast. In theoretical terms, it is optimally efficient, by finalizing blocks in only one voting round. Resulting from this, it should greatly increase the number of transactions per second and guarantee that every block will be instantly finalized.
Since speed without security does not provide any actual value, Algorand designs its network agreement with focus on being able to withstand elongated network partitions and recover very quickly from them, addressing a host of real world attacks. Network partitions are network level attacks (in contrast to protocol level attacks) where an adversary targets the communication links between users, making it hard or impossible for users to interact.
Network attacks can be performed on any decentralized system. Regardless of how a blockchain is designed, if an attacker is powerful enough to maintain a network partition forever, no blocks will ever be produced. The best one can do is increase the cost for the attacker to stall a blockchain.
In PoW the worst case is quite bad. Two chains will form, one in each partition. When the partition heals the lesser chain will go away. All the transaction that appeared there will be reverted. Network attacks can be very subtle. A skilled powerful adversary may allow all traffic except specific protocol messages go through unmolested making partition detection nearly impossible.

Algorand uses Byzantine Agreement but optimized for world-scale and high-performance. (Traditional BA maxes at out at 12 users and requires the participants to be fixed and known ahead of time.) This works under > 2/3 honest majority and does not rely on the participants having synchronized clocks. When honest messages are delivered, worst-case delay agreement is reached within a constant number of steps when the elected leader is malicious, and is reached after two steps when the elected leader is honest.
The protocol is resilient to arbitrary network partitions with unknown length, and recovers fast after the partition is resolved and message delay is restored. By recovering almost instantly from partitions, the Algorand agreement makes it economically expensive to stall the blockchain (since the attacker would need to very frequently pay the cost for disrupting the network).

When an honest leader proposes a block of transactions, the first voting step happens in parallel with the block propagation (i.e. network participants vote immediately after receiving the block). Effectively, after the block propagates through all participating nodes, a certificate is generated in just one step of voting.

To scale the consensus to many network participants, Algorand uses a novel mechanism based on Verifiable Random Functions that allows participants to privately check whether they are selected to participate in the agreement on the next block, and to include a proof of their selection in their network messages.

In Algorand’s protocol, users do not keep any private state except for their private keys, which allows Algorand to replace participants immediately after they send a message. This mitigates targeted attacks on chosen participants after their identity is revealed.

Even if an attacker achieves complete control over the network and dictates which user receives which messages and when, Algorand’s agreement protocol will not fork and the users’ balances will remain secure.

Algorand is designed to work efficiently and securely in a totally permissionless environment, where an arbitrary number of participants are allowed to join and leave the network at any time, without any vetting or permission of any kind.

Source code review
The following code review is based entirely on Algorand private repositories, currently not accessible to the public. We would like to thank Algorand for the kindness of providing us access in order to perform this review as first external party. Due to the private status of the repositories we are restricted from discussing the code logic in any great detail.

Code structure & architecture:
• Code is well structured
• Functions are clean
• Short coding
• No work arounds or hacks

Code formatting and comments:
• Fits a 13inch screen without horizontal scrolling
• Comments are descriptive
• No code out-commented and no code fragments

Maintainability:
• The code is self explanatory and uses appropriate names for variables/functions
• Reusability and testability is well supported

The code follows object oriented analysis and design principles. Files are short (usually less than 300 lines) and focused. Development is straight forward and the code quality is very high.
The code follows the configurability approach and keeps the configurable values separately so that no code changes are required if the values are changed frequently.
It is easy to add extensions with minimal changes to the existing code and the code is modular so that components can be easily replaced.
All used data types are well suited to their purpose from a performance perspective – such as StringBuilder generic collection classes.
As a public blockchain project always requires a high level of security we are pleased to see that Algorand uses best practice methods for authentication, authorization and input data validation against security threats. Especially the kmd (Key Management Daemon) which can run on a secure external machine brings this project to a higher level.
The source code is well organized in folders with good naming and explanations.
A closer look at selected files:

This type of commenting as exemplified above is frequently found in the source files. It explains the logic very precisely and without any room for misunderstandings, which makes further walkthrough of the logic on our part obsolete.
The code follows the typical Open Closed Principle and SRS (Single Responsibility Principle). Functions and classes are well built and dependencies are linked as packages.
Another point worth mentioning is that private repositories for project in development are typically not well documented and lack readme files. This is not the case with Algorand, where even the private repositories have excellent documentation.

It appears that the team is well prepared for a public launch of the repositories. We notice that the repositories use docker to unify the installation process.

With 2171 commits and 142 branches the project is very well grown.

In service.go Algorand defines a service as instance of the agreement protocol. This code is central to the Algorand consensus.

Again, the code is well developed and commented. The team also uses the TODO-Tag, which creates an automatic ToDo-lists for the developers and makes it easy for the team to manage the source code development.
Installation and functional test
The second part of the repository check is to install the system. For this we use for this we use two different target platforms (OS-X and Linux) to assess different installation methods.
We install Algorand on a MacBook Pro 15 (2017), i7 2.8 GHz and 16GB RAM and OS X High Sierra and also on an i7 3.2 GHz with 16GB RAM and Ubuntu 17.04 LTS. Both Systems are equipped with a 512GB SSD.
The installation instruction can be found on https://developer.algorand.org/

Node installation; System: Apple OS-X
After download and extraction of the tar.gz file the installation runs and automatically mitigates any issues with missing directories etc; a very smooth experience:

:./update.sh -i -c stable -p ~/node -d ~/node/data –n
./update.sh: line 102: /Users/xxx/node/algod: No such file or directory
Current Version = 0
Latest Version = 131084
New version found
Update Downloaded to /var/folders/sf/t15_85yx06g29jf2ts1hpw7h0000gn/T/tmp.vhku2NPV/131084.tar.gz
Expanding update…
Validating update…
Starting the new update script to complete the installation…
./update.sh: line 301: pushd: /Users/xxx/node/data: No such file or directory
Failed to archive logs (or none to archive)
./update.sh: line 313: popd: directory stack empty
… Resuming installation from the latest update script
/var/folders/sf/t15_85yx06g29jf2ts1hpw7h0000gn/T/tmp.vhku2NPV/a/bin/update.sh: line 123: /Users/xxx/node/algod: No such file or directory
Current Version = 0
Stopping node…
… node not running
Backing up current binary files…
Backing up current data files from /Users/xxx/node/data…
Installing new binary files…
Installing new data files into /Users/xxx/node/data…
Checking for new ledger in /Users/xxx/node/data
head: /Users/xxx/node/data/wallet-genesis.id: No such file or directory
New genesis ID, resetting wallets
New Ledger – restoring genesis wallets in /Users/xxx/node/data
New Ledger – importing rootkeys for genesis wallets
Imported 0 keys
Applying migration fixups…
Deleting existing log files in /Users/xxx/node/data
Install complete – restart node manually

After configuration of the telemetry, we proceed to start the node:

:./goal node start -d data
Algorand node successfully started!
We then check if the node daemon process is really running:
:pgrep algod
61072

:./goal node status -d data
Last committed block: 299
Time since last block: 0.0s
Sync Time: 0.0s
Last consensus protocol: v2
Next consensus protocol: v2
Round for next consensus protocol: 300
Next consensus protocol supported: true

:./carpenter -d data
Watching file: data/node.log…
could not decode line from JSON: ++++++++++++++++++++++++++++++++++++++++
could not decode line from JSON: Logging Starting
could not decode line from JSON: Telemetry Enabled: 486c33a2-cb1c-44ca-ac8e-746dd8de603f:Dirks-MacBook-Pro-2
could not decode line from JSON: Session: 914dbb7b-1ff0-40fb-80c0-3da891f027f5
could not decode line from JSON: ++++++++++++++++++++++++++++++++++++++++
: ProposalAssembled -300.0.0|
300.0.1: StepTimeout – |
: ProposalFrozen AAAAA-300.0.0|
300.0.2: StepTimeout – |
300.0.3: VoteAttest AAAAA- |
300.0.3: StepTimeout – |
300.0.4: VoteAttest AAAAA- |
300.0.4: StepTimeout – |
300.0.5: VoteAttest AAAAA- |
300.0.5: StepTimeout – |
300.0.6: VoteAttest AAAAA- |
300.0.6: StepTimeout – |
300.0.0: RoundInterrupted – |
: ProposalAssembled -301.0.0|
301.0.0: RoundInterrupted – |
: ProposalAssembled -302.0.0|
302.0.0: RoundInterrupted – |
…(truncated)

Node installation; System: Ubuntu 17.04


Running a private local network in testmode
Although nodes are intended to run in a permissionless network, Algorand provides an option to create a permissioned (private) network for development and test purposes before deploying against the main network.
We start by defining the following private network consisting of two nodes and three wallets:
TestNetwork.json
{
“Genesis”: {
“NetworkName”: “TestNetwork”,
“Wallets”: [
{
“Name”: “Wallet1”,
“Stake”: 50,
“Online”: true
},
{
“Name”: “Wallet2”,
“Stake”: 40,
“Online”: true
},
{
“Name”: “Wallet3”,
“Stake”: 10,
“Online”: false
}
]
},
“Nodes”: [
{
“Name”: “Primary”,
“IsRelay”: true,
“Wallets”: [
{
“Name”: “Wallet1”,
“ParticipationOnly”: false
}
]
},
{
“Name”: “Node”,
“Wallets”: [
{
“Name”: “Wallet2”,
“ParticipationOnly”: false
},
{
“Name”: “Wallet3”,
“ParticipationOnly”: false
}
]
}
]
}
We create the network based on the config file above:

:./goal network create -r ~/net1 -n private -t ./TestNetwork.json
Created new rootkey: /Users/xxx/net1/Wallet1.rootkey
Created new partkey: /Users/xxx/net1/Wallet1.300.1000300.partkey
Created new rootkey: /Users/xxx/net1/Wallet2.rootkey
Created new partkey: /Users/xxx/net1/Wallet2.300.1000300.partkey
Created new rootkey: /Users/xxx/net1/Wallet3.rootkey
Created new partkey: /Users/xxx/net1/Wallet3.300.1000300.partkey
Network private created under /Users/xxx/net1

We then proceed to start our network with two nodes:

:./goal network start -r ~/net1
Network Started under /Users/drdirkbauer/net1

Now we need to check the status of our network with our nodes ‘Primary’ and ‘Node’:

:./goal network status -r ~/net1
[Primary]
Last committed block: 308
Time since last block: 2.4s
Sync Time: 0.0s
Last consensus protocol: v4
Next consensus protocol: v4
Round for next consensus protocol: 309
Next consensus protocol supported: true

[Node]
Last committed block: 308
Time since last block: 2.4s
Sync Time: 0.0s
Last consensus protocol: v4
Next consensus protocol: v4
Round for next consensus protocol: 309
Next consensus protocol supported: true

The nodes can be configured as standard or relay. The standard node has two modes: archive and non-archive. The archive version will store the complete blockchain on the system, the non-archive version only stores the information that is needed to run the node.
The relay node will connect with the TestNet and always stores the complete blockchain on the system.
We check what wallets we have associated with our ‘Primary’ node:

:./goal wallet list -d ~/net1/Primary

#

Wallet: unencrypted-default-wallet
ID: 04df26305aa1337dcf6e787622b78cce

#

As expected there is only one wallet according to the configuration provided initially for the network. We try out to create another wallet for this node:

:./goal wallet new MyWallet -d ~/net1/Primary
Please choose a password for wallet ‘MyWallet’:
Please confirm the password:
Creating wallet…
Created wallet ‘MyWallet’
Your new wallet has a backup phrase that can be used for recovery.
Keeping this backup phrase safe is extremely important.
Would you like to see it now? (Y/n): Y
Your backup phrase is printed below.
Keep this information safe — never share it with anyone!
patient stand liar plunge hidden ….(truncated seed phrase)

We set our new wallet as default for this node:

:./goal wallet -f MyWallet -d ~/net1/Primary
And create two addresses for the new default wallet
:./goal account new -d ~/net1/Primary
Created new account with address ESIVU7EFBABFHE4ZGAYHYENRORD7DCN34JAHHVF5NJP3HDA6O6WTN35SXY
: ./goal account new -d ~/net1/Primary
Created new account with address RZTAVIJEF7XNNDWUAMORBTLKVHGOA4WCJV7VRYR2XJ4RO23LZ5IWQQREO4

We proceed to create a transaction between the two addresses of this wallet:

:./goal clerk send -s -o ./raw.tx -a 100 -f ESIVU7EFBABFHE4ZGAYHYENRORD7DCN34JAHHVF5NJP3HDA6O6WTN35SXY -t RZTAVIJEF7XNNDWUAMORBTLKVHGOA4WCJV7VRYR2XJ4RO23LZ5IWQQREO4 -d ~/net1/Primary
Please enter the password for wallet ‘MyWallet’: …

We check if the transaction was successful:

:curl -s -X POST –data-binary “@./raw.tx” -H “X-Algo-API-Token: $(cat ~/net1/Primary/algod.token)” “http://$(cat ~/net1/Primary/algod.net)/v1/transactions”
TransactionPool.Remember: TransactionPool.Remember: Insufficient funds – The total pending transactions from the address require 309 microAlgos but the account only has 0 microAlgos

As expected, the transaction did not go through since we never funded this wallet.
Finally we stop the execution of the private network after running both node types for more than 48h without any kind of stability issues:

:./goal network stop -r ~/net1
Network Stopped under /Users/drdirkbauer/net1
Before stopping we also tried out the remaining set of commands for the Goal CLI without encountering any issues what so ever. Everything works according to specifications.
Also worth mentioning is that we were very impressed by the consistency of the various Goal commands in regards to options/parameters. Compare this to even Linux, where one often is forced to a specific order of options which is not consistent.
Algorand comes across as a very solid and mature system that provides a very lean experience across all parts.

RestAPI
The RestAPI can be used on the algod (Algorand protocol daemon) process or kmd (key management daemon) process. The algod process starts automatically when the node starts. The kmd process needs to be invoked by Goal. The kmd is primarly for key management and signing of transactions and can run on seperate machine (increase security). A nice concept that supports critical business processes.
We try out the RestAPI by signing a transaction and it works as exactly as expected.
SDK
Algorand offers SDKs for three major development languages, Go, JS (node.js) and Java. The Go SDK (which we used) is available on Algorand GitHub. The SDK can work against kmd and algod (see RestAPI).
We install the GO SDK from GitHub and try it out (prerequisite is an installed GO language library).

: go get -u github.com/algorand/go-algorand-sdk/…
Then we start our node and key management daemon again:
:./goal node start -d ~/algorand/TestNet/data/relay
Algorand node successfully started!

:./goal kmd start -d ./data/relay
Successfully started kmd

Conclusion
Algorand is founded by Silvio Micali, a cryptography pioneer and MIT professor, and led by a team of accomplished leaders in technology, business leaders, and respected technology investors. This obviously brings very high expectations on Algorand, which is fully matched by what we see from their product at this stage in the roadmap.
Business partner TOP Network, a full-stack decentralized cloud communication service with 60 million users globally, actively participated in the Algorand TestNet and recently announced a partnership with Algorand to build next-gen layer 2 offerings for its user base. Other real world adoption cases within the finance and real estate industries are underway as well, which tells us that Algorand is a product with real demand from clients and will have no issues reaching the market with its solid management and funding.
After previously bringing several key components to the blockchain ecosystem which are a now widely adopted, Algorand advances blockchain technology further by introducing its recovery mechanism for network partition attacks, and makes it unreasonably costly of an adversary to disrupt the network for any significant amount of time.
In terms of test experience, Algorand impresses immensely and displays less glitches than even software from global vendors such as Apple and Microsoft (which we have experience from on daily basis in our various customer projects). In terms of product maturity, for a TestNet, it is without any doubt the best we have seen in the blockchain space so far.
The well documented code and development site is characteristic for a project that is serious about actual adoption and supports this by providing a lean experience both to developers and operators.
We are convinced that Algorand is on track both technically and commercially to become a major success and Algorand is one of very few blockchain platforms where we would be interested in participating as node operators once MainNet is released.

 

Stay Connected

 
cryptodiffer logo
rss subscription
 
© 2024 InCodeWeTrust