Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
Background
Two weeks ago Blockchain Academy TLV kicked off its inaugural session. During our first meeting, Leonid Beder discussed blockchain basics, and live coded a basic blockchain implementation in Typescript. Leonid added an Express server that would let us interact with our blockchain easily via a REST API. The implementation included the following functionality:
Posting a Node: A blockchain is a distributed, decentralized database, where every node on the network holds a complete copy of transaction history. This method allows us to add nodes to the network.
Post a Transaction: A blockchain serves as a record of transaction history. Although a transaction can be defined broadly, itâs most popular use case is a transfer of funds from user A to user B. This method lets us create transactions, waiting to be mined.
Mine a Block: Transactions arenât reflected across the network immediately. We need to invest computational power into validating transactions. This is called Proof of Work. Mining a block is the action of performing âProof Of Workâ on all of the transactions that have recently been emitted but not yet validated. No free lunches in cryptocurrencies ;)
Consensus: Consensus is the process of all nodes reaching agreement on the current state of the network. We choose âthe longest chainâ (Greedy Heaviest Observed Subtree) approach. This approach states that all nodes will accept the blockchain of the node with the most blocks. The rationale behind this, is that the longest blockchain has the most computational power invested in it (remember, we require blocks to be validated via PoW), and is therefore the most reliable / believable.
Although it was a lot of new material to process in a hour, I was hooked :) Towards the end of the workshop Leonid announced a surprise!
There would be a competition to see who could make the most creative and âawesomeâ pull request to the basic blockchain we had just built.
My work over the past 2Â weeks
I had been itching to learn more about blockchain, and believe that building one is the best way to do that. I set out to build a blockchain inspired by the Ethereum implementation with the following features:
- Accounting system - users will be able to register accounts (external accounts) with a balance, and initiate transfers of funds. Additionally, users can register contract accounts and deploy smart contracts across the network
- Transaction-based state machine
- Secured and validated transactions and state transitions
- Enable users to write smart contracts and decentralized applications where they can create their own arbitrary rules for ownership, transaction formats and state transition functions.
Accounts
The global shared state of nodes on the network is composed of accounts. Accounts holds important information such as
- address: this will serve as the name of the account, similar to what we did in the workshop.
- balance: amount of funds owned by the account
- nonce: If the account is an externally owned account, this number represents the number of transactions sent from the accountâs address.
My blockchain implementation has 2 different types of accounts:
- External accounts, which are controlled by private keys (via RSA encryption)
- Contract accounts, which are controlled by their contract code.
Single Shared State Across Network
Accounts are public, and you can view any account given its address, and node it was registered on. I made accounts âglobalâ by informing all nodes of the creation of an account on the network. So when account transactions are dispatched to a node, I propagate that transaction to all nodes on the network. This way, the blockchain is truly decentralized, and we donât depend on single nodes for valuable information like account existence or account balances. Essentially we have created a singular âshared-stateâ between nodes.
We register each account on every node, so that it is âglobalâDifferences between External and Contract Accounts
The main difference between both types of accounts is rooted in how they can communicate with other accounts across the network. An external account can communicate in 2Â ways
- Messaging other external accounts (i.e. a transaction which moves funds from account A to B).
- Invoking method execution on contract accounts. These methods vary, as they are solely dependent on the contract author and the contract that he / she created.
It is important to clarify that contract accounts, in contrast to external accounts, cannot explicitly dispatch transactions to the network. Instead, contract accounts can only emit transactions in response to other transactions they have received.
- External Accounts
Authenticating accounts is done via RSA encryption. Upon account initialization a private, public key pair is created and written to disk.
Keys being created in the ExternalAccounts constructor. On the right, we view the public key
These keys are used to digitally sign outgoing transaction requests with the account credentials. A more robust implementation would always ask an account, whether or not he wants to sign the request before sending it. You can view a rudimentary implementation of this in requestAuthForTransaction.sh.
An assumption Iâve made for this implementation is that all accounts agree to sign all transactions requests with their credentials.
2. Contract Accounts
Contract accounts are controlled by their code. They simply execute a specific piece of code when invoked, and have direct control over their balance.
One of the challenges here was figuring out how to support this in a dynamic, distributed, decentralized, trust less manner. Ethereum uses a globally accessible virtual machine (given a pointer to the contractâs byte code) to execute the contractâs code. But JS doesnât have a globally accessible VM out of the box for all the nodes to refer to. I initially tried to deploy a contract to all nodes on the network as a stringified JSON object, so that contract execution could be invoked independently on each node by parsing the received object. Unfortunately, JSON.stringify ignores methods and functions, therefore stripping smart contracts of their functionality on writes. My workaround for sending contracts dynamically (not hard coded on every node instance) across the network was as follows:
Deploying a Contract
- Write a smart contract as a plain JSÂ object.
2. Wrap it with parenthesis to make it a string, and remove all newlines so it can be processed via the built in JS eval method when other nodes receive it.
3. Send the string as data to all nodes on the network.
Deploying a contract across the network
This allows nodes to create contracts on the fly and deploy them across the network. đđđ
Writing contract updates
Initially we can parse the stringified contract by using the built-in JS eval method, which takes a string and evaluates it as a JS statement.
After executing a method that mutates contract state (i.e. changes balance of contract) we want to store the contract in its entirety, without losing access to our methods.
Therefore, we will use the JSON stringify method, and pass a custom âreplacerâ function, instructing it on how to stringify functions.
In the future, to read the specially stringified version of the contract we will pass a custom âreviverâ to the JSON.parse method.
Emitting Transactions via Contract Execution
Some contract mutations may only update the internal state of the contract. Other contract executions can âemitâ transactions that effect the state of the network. For example, a contract holding funds (contracts govern their own funds) can send them to a specific user upon a certain condition being met. These emitted transactions are listened for, and placed into the mining queue, similar to other transactions in the network. They must be validated before being written to the blockchain. The flow looks like this:
An emitted transaction via a contract mutation request, appended to the mempoolSmart Contracts with Permissions
Calling a smart contract simply invokes a method that results in a transaction emission. Contracts are deployed globally and weâd like an easy way to control who can invoke contract methods. Weâd like to enable users to build contracts that support user permissions. For example in an election, weâd only want eligible users to be able to vote (we can determine eligibility however we see fit.). Because all requested transactions are digitally signed via RSA encryption by the requester, we can safely check the user who requested to execute the contract and decide whether or not he is authorized to do so.
DAOVotingContract.ts example with permissionsTransaction Validation
During the first workshop we implemented a raw version of transactions. Because we had no accounts, no form of identification, and no balances to update, they had no meaning. After implementing the above, we can now verify the legality, or âcorrectnessâ of a requested transaction
State Transition Function
Ethereumâs white paper describes a cryptocurrency ledger as a state transition system, where state is composed of ownership status of currency within the system. In my implementation every node has accounts who hold a specific balance. But how does state (balance) change over time? Ethereum specifies a State Transition Function as follows:
Illustration from the Ethereum White Paper
In our implementation we will take a similar approach to validating state transitions. We will:
- Check if a transaction adheres to the requested structure and has all the necessary values.
- All transactions have a senderNodeId and a senderAddress. Although this is an unsafe assumption, for the current implementation and for lack of a proper user client, we will assume that all accounts agree and digitally sign all outgoing transaction requests with their credentials. Before being submitted to the mining queue, we will verify this digital signature.
- Check that the nonce matches the nonce in the senderâs account.
After verifying the transaction via the stateTransitionValidation method we can add the transaction to the mining queue and mine. It is important to note that these transactions have not yet mutated the network state. Upon consensus, if these transactions belong to the longest chain, and it is a transaction that moves funds we will validate that the sender has an adequate account balance. An example of filtering illegal transactions (sender A sending more funds then he owns) can be see in adequateFunds.sh.
To visualize this process:
Example Contracts
Now that our blockchain has accounts, validated transactions and a way to create and propagate contracts across the network we can look at some real contracts. These contracts are pretty straight forward, and showcase the flexibility and potential of authoring smart contracts on the blockchain.
Counter Contract
To start things off letâs look at a simple contract that acts as a counter. Every time the contractâs incrementValue method is called we will increment the counter. Notice, that anyone can invoke this contract code.
We invoke the contract code by dispatching a mutateContract/:CounterContract PUT request. This contract has its own internal state which it governs. When incrementValue is called the contract state emits a transaction, requesting to mutate the contract state. After being mined, the mutation is written to the blockchain, so that we have a record of who used the contract (initiated the mutation request) and how the contract was used.
This contract can be executed via the Postman client or by running the counter_contract.sh script in the shell-scripts directory.
Transfer funds after arbitrary date Contract
A more realistic scenario for a smart contract is moving funds from account A to account B. The following contract is based on the scenario that Bob wants to transfer 400 coins to Alice, after an arbitrary date has passed. Instead of using a third party service, or escrow system, he can create a smart contract that checks when the date has passed, and initiate a transfer of funds.
When the contractâs moveFunds method is invoked it will check the date, see that it has passed and transfer funds to Alice.
This contract can be executed via the Postman client or by running the move_funds_after_data_contract.sh script in the shell-scripts directory.
DAO Vote for Bonus Contract
This scenario involves a DAO (Decentralized autonomous organization) that wants to give one of its employees a bonus. Because this DAO is a completely fair organization đđđ, we should vote on who is deserving of the bonus.
But remember, the blockchain is a public ledger! Therefore, the moment we upload to contract to the network, anyone can see it, and make calls to the contract code. Weâd like a way to restrict the voting to only the DAOâs employees. As I mentioned earlier, every request with an accounts credentials, is digitally signed by that account, with their private key. This way, it is easy to verify the voters true origin. So this contract has an âauthorizedVotersâ field which we will check against, every time an account tries to cast a vote.
This contract can be executed via the Postman client or by running the voting_permissions_contract.sh script in the shell-scripts directory.
These are only several examples of smart contracts. The current structure allows anyone to upload any contract (as long as it adheres to parsable format I am using), deploy it to the network in session, and start executing it. We can create contracts for elections, distributed file storage and more.
Conclusion
Programming this proof-of-concept blockchain was quite a challenge! It is still far from âproductionâ ready, and can be improved and secured in various ways. I had a great time researching the concepts, and learning about blockchain implementations and mechanisms.
A huge thank you, to Leonid Beder for the graceful blockchain introduction, and to Kin Contributors, Orbs and Samsung Next for organizing Blockchain Academy.
You can check out the full code repository here.
Lastly, if you have made it this far, thanks for sticking with it đ€đ€đđđđŒâïžđŒ
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.