Daisy is a simple, but fully featured blockchain with a pluggable VM. The goal of Daisy is to make it trivially simple to build a side-chain which can accept thousands of transactions per second. Daisy is backed by ipfs which makes it trivially easy for anyone to read, verify or explore the chain. We have designed Daisy to easily bridge to and from other block chains (e.g. Ethereum), so clients can easily move assets on to and off of a Daisy chain.
Installation
If available in Hex, the package can be installed
by adding daisy to your list of dependencies in mix.exs:
defdepsdo[{:daisy,"~> 0.1.0"}]end
Starting Daisy
To start Daisy in leader mode, run:
> mix daisy.leader
or as a follower:
> mix daisy.follower
In either case, you can also start the REST API server:
> mix daisy.leader --api
Design Mantras
Daisy aims to be a side-chain. We have a few important design mantras to guide our process:
Bring your own Bespoke VM. Anyone who builds a Daisy chain can incorporate whatever VM fits that business application. For example, you could build a ZombieKittens VM that exposes sire_kitten(kitten_uuid), fight_kitten(kitten_uuid, target_uuid), both of which are implemented in Elixir. Anyone who submits a transaction to the chain is submitting intent, not arbitrary code. Which brings us to:
Forks are Patches. Transactions are intent-based given a Daisy VM. For example, a Payment VM might have a transaction: transfer_funds(from, to) or a Chess VM: move_pawn(game, location). When there are bugs in the implementation of a function, it should be easily agreed upon to make a change if it matches the original intent for the user. Patches must be agreed upon by the community, and the goal is that most patches should be quickly accepted.
Ethereum Bridge Contracts. Daisy is just a side-chain; it's meant to interact with one or more main chains. The root hash of every mined block is submitted to an Ethereum Bridge Contract. This contract can, via evidence provided by merkle-proofs, verify that data exists on the side-chain. For instance, this allows your chain to verifiable move Ether into your Daisy side-chain. The end-user could add Ether to the bridge contract, which would be held as pending until a merkle-proof from a new root hash included the user's updated side-chain balance. These bridges allow Daisy side-chains to interact with Ethereum, Bitcoin and all other chains.
Elected-Leader Sidechain. We belive that adding a little centralization can go a long way. In Daisy, token holders on a main chain (e.g. the Ethereum Bridge Contract) elect a leader who mines all blocks. To submit a transction, you pass the transaction to the leader directly (and get an immediate pending result). Anyone can run a Daisy node and verify that the given blocks are accurate to the protocol. If the leader posts any inaccurate blocks, the community immediately holds a new leader election in the bridge contract. The central leader allows the entire system to be free, instant and verifiable.
IPFS. All blockchains need to store data in a content-addressable structure and distribute those blocks in a peer-to-peer system. Can't somebody else do it? Well, they did, and it's IPFS. Daisy relies on IPFS for distributing new blocks, IPNS for information about the current block hash and even allows users to explore the blockchain through the web at https://ipfs.io.
Terminology
Block
A block is a collection of transactions which are run from the final state of a parent block. Each transaction generates a receipt describing how it ran.
Transaction, Invokation and Signature
A function invokation signed by a user. Transactions effect the total state of the chain. The `Invokation` specifies what function and arguments to call in the VM Runner, and the signature provides an ECDSA signature to prove who is the owner of the message.
Receipt
After a transaction is run, a receipt is generated. The receipt described what happened during the execution of the transaction. A receipt includes logs, the final state after running, etc.
Daisy VM
A VM describes how your world works in Daisy. For a VM, you specify a `Runner` which is responsible for function invokations from `Transaction`s, and you specify a `Reader` which describes how to read from your world state.
Proof
To interact with other chains (e.g. Ethereum), it's often necessary to state
that a value exists in a Daisy side-chain without having to include the entire Daisy chain in the Ethereum blockchain. `Proof` are nodes in the IPFS tree that prove a given leaf has a given value rolled up a block hash.
Serializer
Some data, such as transactions and receipts, are serialized before being pushed onto the blockchain. This is because, among other reasons, they need a digital signature and thus a canonical representation. We currently support JSON serialization.
Daisy VM
To implement a bespoke Daisy VM, you need to build two modules, a Reader and a Runner. Here's a simplified VM for tic-tac-toe, illustrating a read and run_transaction implementation. For more information, see the hex docs.
defmoduleTieTacToedo@behaviourDaisy.Reader@behaviourDaisy.Runner# Reads a gameboard based on game_uuid@specread(String.t,[String.t],Daisy.Storage.root_hash)::{:ok,any()}|{:erorr,any()}defread("board",[game_uuid],storage)do# Read game from storagewith{:ok,game}<-Daisy.Storage.get(storage,"game:#{game_uuid}")|>deserializedo# Pass back result to caller{:ok,game|>pretty_print}endend# Allows a player to move in tic-tac-toedefrun_transaction(%Daisy.Data.Invokation{function: "play",args: [game_uuid,position]},storage_0,player)do# Get the current game statewith{:ok,game}<-Daisy.Storage.get(storage_0,"game:#{game_uuid}")|>deserializedo# Check it's the player's turnunlessgame.turn==playerdo{:ok,%{status: :failure,logs: ["Not your turn #{player}!"]}}else# Make the move for the playerupdated_game=game|>Map.put(game,:moves,[position|>String.to_integer,game.moves])|>Map.put(game,:turn,game|>next_turn)# Update the new game statewith{:ok,storage_1}<-Daisy.Storage.put(storage_0,"game:#{game_uuid}",updated_game|>serialize)do# Return success and logs{:ok,%{status: :success,final_storage: storage_1,logs: ["Player #{player} placed piece at #{position}"]}}endendendendend
API
Daisy comes with a JSON-API to communicate with a node.
Reading from Daisy Blocks
# Read from current block
curl http://localhost:2335/read/:my_func>/:my_arg_1/:my_arg_2/...
{"result" =>"good"}
# Read from specified block
curl http://localhost:2335/read/block/:block_hash/:my_func/:my_arg_1/:my_arg_2/...
{"result" =>"good"}
请发表评论