diff --git a/docs/guide/basecoin-basics.md b/docs/guide/basecoin-basics.md index 9ecb08c44..af3cd8308 100644 --- a/docs/guide/basecoin-basics.md +++ b/docs/guide/basecoin-basics.md @@ -1,7 +1,8 @@ # Basecoin Basics Here we explain how to get started with a simple Basecoin blockchain, -and how to send transactions between accounts using the `basecoin` tool. +how to send transactions between accounts using the `basecoin` tool, +and what is happening under the hood. ## Install @@ -80,14 +81,93 @@ basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.jso See `basecoin tx send --help` for additional details. -## Plugins +For a better understanding of the options, it helps to understand the underlying data structures. -The `tx send` command creates and broadcasts a transaction of type `SendTx`, -which is only useful for moving tokens around. -Fortunately, Basecoin supports another transaction type, the `AppTx`, -which can trigger code registered via a plugin system. +## Accounts -In the [next tutorial](example-plugin.md), -we demonstrate how to implement a plugin -and extend the CLI to support new transaction types! -But first, you may want to learn a bit more about [Basecoin's design](basecoin-design.md) +The Basecoin state consists entirely of a set of accounts. +Each account contains an ED25519 public key, +a balance in many different coin denominations, +and a strictly increasing sequence number for replay protection. +This type of account was directly inspired by accounts in Ethereum, +and is unlike Bitcoin's use of Unspent Transaction Outputs (UTXOs). +Note Basecoin is a multi-asset cryptocurrency, so each account can have many different kinds of tokens. + +```golang +type Account struct { + PubKey crypto.PubKey `json:"pub_key"` // May be nil, if not known. + Sequence int `json:"sequence"` + Balance Coins `json:"coins"` +} + +type Coins []Coin + +type Coin struct { + Denom string `json:"denom"` + Amount int64 `json:"amount"` +} +``` + +Accounts are serialized and stored in a Merkle tree under the key `base/a/
`, where `` is the address of the account. +Typically, the address of the account is the 20-byte `RIPEMD160` hash of the public key, but other formats are acceptable as well, +as defined in the [tendermint crypto library](https://github.com/tendermint/go-crypto). +The Merkle tree used in Basecoin is a balanced, binary search tree, which we call an [IAVL tree](https://github.com/tendermint/go-merkle). + +## Transactions + +Basecoin defines a simple transaction type, the `SendTx`, which allows tokens to be sent to other accounts. +The `SendTx` takes a list of inputs and a list of outputs, +and transfers all the tokens listed in the inputs from their corresponding accounts to the accounts listed in the output. +The `SendTx` is structured as follows: + +```golang +type SendTx struct { + Gas int64 `json:"gas"` + Fee Coin `json:"fee"` + Inputs []TxInput `json:"inputs"` + Outputs []TxOutput `json:"outputs"` +} + +type TxInput struct { + Address []byte `json:"address"` // Hash of the PubKey + Coins Coins `json:"coins"` // + Sequence int `json:"sequence"` // Must be 1 greater than the last committed TxInput + Signature crypto.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx + PubKey crypto.PubKey `json:"pub_key"` // Is present iff Sequence == 0 +} + +type TxOutput struct { + Address []byte `json:"address"` // Hash of the PubKey + Coins Coins `json:"coins"` // +} +``` + +Note the `SendTx` includes a field for `Gas` and `Fee`. +The `Gas` limits the total amount of computation that can be done by the transaction, +while the `Fee` refers to the total amount paid in fees. +This is slightly different from Ethereum's concept of `Gas` and `GasPrice`, +where `Fee = Gas x GasPrice`. In Basecoin, the `Gas` and `Fee` are independent, +and the `GasPrice` is implicit. + +In Tendermint, the `Fee` is meant to be used by the validators to inform the ordering +of transactions, like in bitcoin. And the `Gas` is meant to be used by the application +plugin to control its execution. There is currently no means to pass `Fee` information +to the Tendermint validators, but it will come soon... + +Note also that the `PubKey` only needs to be sent for `Sequence == 0`. +After that, it is stored under the account in the Merkle tree and subsequent transactions can exclude it, +using only the `Address` to refer to the sender. Ethereum does not require public keys to be sent in transactions +as it uses a different elliptic curve scheme which enables the public key to be derived from the signature itself. + +Finally, note that the use of multiple inputs and multiple outputs allows us to send many +different types of tokens between many different accounts at once in an atomic transaction. +Thus, the `SendTx` can serve as a basic unit of decentralized exchange. When using multiple +inputs and outputs, you must make sure that the sum of coins of the inputs equals the sum of +coins of the outputs (no creating money), and that all accounts that provide inputs have signed the transaction. + +## Conclusion + +In this guide, we introduced the `basecoin` tool, demonstrated how to use it to send tokens between accounts, +and discussed the underlying data types for accounts and transactions, specifically the `Account` and the `SendTx`. +In the [next guide](basecoin-plugins.md), we introduce the basecoin plugin system, which uses a new transaction type, the `AppTx`, +to extend the functionality of the Basecoin system with arbitrary logic. diff --git a/docs/guide/basecoin-design.md b/docs/guide/basecoin-design.md deleted file mode 100644 index a9bf5d503..000000000 --- a/docs/guide/basecoin-design.md +++ /dev/null @@ -1,95 +0,0 @@ -# Basecoin Design - -Basecoin is designed to be a simple cryptocurrency application with limited built-in functionality, -but with the capacity to be extended by arbitrary plugins. -Its basic data structures are inspired by Ethereum, but it is much simpler, as there is no built-in virtual machine. - -## Accounts - -The Basecoin state consists entirely of a set of accounts. -Each account contains an ED25519 public key, -a balance in many different coin denominations, -and a strictly increasing sequence number for replay protection. -This type of account was directly inspired by accounts in Ethereum, -and is unlike Bitcoin's use of Unspent Transaction Outputs (UTXOs). -Note Basecoin is a multi-asset cryptocurrency, so each account can have many different kinds of tokens. - -```golang -type Account struct { - PubKey crypto.PubKey `json:"pub_key"` // May be nil, if not known. - Sequence int `json:"sequence"` - Balance Coins `json:"coins"` -} - -type Coins []Coin - -type Coin struct { - Denom string `json:"denom"` - Amount int64 `json:"amount"` -} -``` - -Accounts are serialized and stored in a Merkle tree using the account's address as the key, -In particular, an account is stored in the Merkle tree under the key `base/a/`, -where `` is the address of the account. -In Basecoin, the address of an account is the 20-byte `RIPEMD160` hash of the public key. -The Merkle tree used in Basecoin is a balanced, binary search tree, which we call an [IAVL tree](https://github.com/tendermint/go-merkle). - -## Transactions - -Basecoin defines a simple transaction type, the `SendTx`, which allows tokens to be sent to other accounts. -The `SendTx` takes a list of inputs and a list of outputs, -and transfers all the tokens listed in the inputs from their corresponding accounts to the accounts listed in the output. -The `SendTx` is structured as follows: - -```golang -type SendTx struct { - Gas int64 `json:"gas"` - Fee Coin `json:"fee"` - Inputs []TxInput `json:"inputs"` - Outputs []TxOutput `json:"outputs"` -} - -type TxInput struct { - Address []byte `json:"address"` // Hash of the PubKey - Coins Coins `json:"coins"` // - Sequence int `json:"sequence"` // Must be 1 greater than the last committed TxInput - Signature crypto.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx - PubKey crypto.PubKey `json:"pub_key"` // Is present iff Sequence == 0 -} - -type TxOutput struct { - Address []byte `json:"address"` // Hash of the PubKey - Coins Coins `json:"coins"` // -} -``` - -There are a few things to note. First, the `SendTx` includes a field for `Gas` and `Fee`. -The `Gas` limits the total amount of computation that can be done by the transaction, -while the `Fee` refers to the total amount paid in fees. -This is slightly different from Ethereum's concept of `Gas` and `GasPrice`, -where `Fee = Gas x GasPrice`. In Basecoin, the `Gas` and `Fee` are independent, -and the `GasPrice` is implicit. - -In Tendermint, the `Fee` is meant to be used by the validators to inform the ordering -of transactions, like in bitcoin. And the `Gas` is meant to be used by the application -plugin to control its execution. There is currently no means to pass `Fee` information -to the Tendermint validators, but it will come soon... - -Second, notice that the `PubKey` only needs to be sent for `Sequence == 0`. -After that, it is stored under the account in the Merkle tree and subsequent transactions can exclude it, -using only the `Address` to refer to the sender. Ethereum does not require public keys to be sent in transactions -as it uses a different elliptic curve scheme which enables the public key to be derived from the signature itself. - -Finally, note that the use of multiple inputs and multiple outputs allows us to send many -different types of tokens between many different accounts at once in an atomic transaction. -Thus, the `SendTx` can serve as a basic unit of decentralized exchange. When using multiple -inputs and outputs, you must make sure that the sum of coins of the inputs equals the sum of -coins of the outputs (no creating money), and that all accounts that provide inputs have signed the transaction. - -## Plugins - -Basecoin actually defines a second transaction type, the `AppTx`, -which enables the functionality to be extended via custom plugins. -To learn more about the `AppTx` and plugin system, see the [plugin design document](plugin-design.md). -To implement your first plugin, see [plugin tutorial](example-plugin.md). diff --git a/docs/guide/basecoin-plugins.md b/docs/guide/basecoin-plugins.md new file mode 100644 index 000000000..cc78d246a --- /dev/null +++ b/docs/guide/basecoin-plugins.md @@ -0,0 +1,162 @@ +# Basecoin Plugins + +In the [previous guide](basecoin-basics.md), +we saw how to use the `basecoin` tool to start a blockchain and send transactions. +We also learned about `Account` and `SendTx`, the basic data types giving us a multi-asset cryptocurrency. +Here, we will demonstrate how to extend the `basecoin` tool to use another transaction type, the `AppTx`, +to send data to a custom plugin. In this case we use a simple plugin that takes a single boolean argument, +and only accept the transaction if the argument is set to `true`. + +## Example Plugin + +The design of the `basecoin` tool makes it easy to extend for custom functionality. +To see what this looks like, install the `example-plugin` tool: + +``` +cd $GOPATH/src/github.com/tendermint/basecoin +go install ./docs/guide/src/example-plugin +``` + +The `example-plugin` tool is just like the `basecoin` tool. +They both use the same library of commands, including one for signing and broadcasting `SendTx`. +See `example-plugin --help` for details. + +A new blockchain can be initialized and started just like with `basecoin`: + +``` +example-plugin init +example-plugin start +``` + +The default files are stored in `~/.basecoin-example-plugin`. +In another window, we can send a `SendTx` like we are used to: + +``` +example-plugin tx send --to 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 --amount 1mycoin +``` + +But the `example-plugin` tool has an additional command, `example-plugin tx example`, +which crafts an `AppTx` specifically for our example plugin. +This command lets you send a single boolean argument: + +``` +example-plugin tx example --amount 1mycoin +example-plugin tx example --amount 1mycoin --valid +``` + +The first transaction is rejected by the plugin because it was not marked as valid, while the second transaction passes. +We can build plugins that take many arguments of different types, and easily extend the tool to accomodate them. +Of course, we can also expose queries on our plugin: + +``` +example-plugin query ExamplePlugin.State +``` + +Note the `"value":"0101"`. This is the serialized form of the state, +which contains only an integer, the number of valid transactions. +If we send another transaction, and then query again, we will see the value increment: + +``` +example-plugin tx example --valid --amount 1mycoin +example-plugin query ExamplePlugin.State +``` + +The value should now be `0102`, because we sent a second valid transaction. +Notice how the result of the query comes with a proof. +This is a Merkle proof that the state is what we say it is. +In a latter [guide on InterBlockchain Communication](ibc.md), +we'll put this proof to work! + + +Now, before we implement our own plugin and tooling, it helps to understand the `AppTx` and the design of the plugin system. + +## AppTx + +The `AppTx` is similar to the `SendTx`, but instead of sending coins from inputs to outputs, +it sends coins from one input to a plugin, and can also send some data. + +```golang +type AppTx struct { + Gas int64 `json:"gas"` + Fee Coin `json:"fee"` + Input TxInput `json:"input"` + Name string `json:"type"` // Name of the plugin + Data []byte `json:"data"` // Data for the plugin to process +} +``` + +The `AppTx` enables Basecoin to be extended with arbitrary additional functionality through the use of plugins. +The `Name` field in the `AppTx` refers to the particular plugin which should process the transaction, +and the `Data` field of the `AppTx` is the data to be forwarded to the plugin for processing. + +Note the `AppTx` also has a `Gas` and `Fee`, with the same meaning as for the `SendTx`. +It also includes a single `TxInput`, which specifies the sender of the transaction, +and some coins that can be forwarded to the plugin as well. + +## Plugins + +A plugin is simply a Go package that implements the `Plugin` interface: + +```golang +type Plugin interface { + + // Name of this plugin, should be short. + Name() string + + // Run a transaction from ABCI DeliverTx + RunTx(store KVStore, ctx CallContext, txBytes []byte) (res abci.Result) + + // Other ABCI message handlers + SetOption(store KVStore, key string, value string) (log string) + InitChain(store KVStore, vals []*abci.Validator) + BeginBlock(store KVStore, hash []byte, header *abci.Header) + EndBlock(store KVStore, height uint64) (res abci.ResponseEndBlock) +} + +type CallContext struct { + CallerAddress []byte // Caller's Address (hash of PubKey) + CallerAccount *Account // Caller's Account, w/ fee & TxInputs deducted + Coins Coins // The coins that the caller wishes to spend, excluding fees +} +``` + +The workhorse of the plugin is `RunTx`, which is called when an `AppTx` is processed. +The `Data` from the `AppTx` is passed in as the `txBytes`, +while the `Input` from the `AppTx` is used to populate the `CallContext`. + +Note that `RunTx` also takes a `KVStore` - this is an abstraction for the underlying Merkle tree which stores the account data. +By passing this to the plugin, we enable plugins to update accounts in the Basecoin state directly, +and also to store arbitrary other information in the state. +In this way, the functionality and state of a Basecoin-derived cryptocurrency can be greatly extended. +One could imagine going so far as to implement the Ethereum Virtual Machine as a plugin! + +For details on how to initialize the state using `SetOption`, see the [guide to using the basecoin tool](basecoin-tool.md#genesis). + + +## Implement your own + +To implement your own plugin and tooling, make a copy of `docs/guide/src/example-plugin`, +and modify the code accordingly. Here, we will briefly describe the design and the changes to be made, +but see the code for more details. + +First is the `main.go`, which drives the program. It can be left alone, but you should change any occurences of `example-plugin` +to whatever your plugin tool is going to be called. + +Next is the `cmd.go`. This is where we extend the tool with any new commands and flags we need to send transactions to our plugin. +Note the `init()` function, where we register a new transaction subcommand with `RegisterTxSubcommand`, +and where we load the plugin into the basecoin app with `RegisterStartPlugin`. + +Finally is the `plugin.go`, where we provide an implementation of the `Plugin` interface. +The most important part of the implementation is the `RunTx` method, which determines the meaning of the data +sent along in the `AppTx`. In our example, we define a new transaction type, the `ExamplePluginTx`, which +we expect to be encoded in the `AppTx.Data`, and thus to be decoded in the `RunTx` method, and used to update the plugin state. + +For more examples and inspiration, see our [repository of example plugins](https://github.com/tendermint/basecoin-examples). + +## Conclusion + +In this guide, we demonstrated how to create a new plugin and how to extend the +`basecoin` tool to start a blockchain with the plugin enabled and send transactions to it. +In the next guide, we introduce a [plugin for Inter Blockchain Communication](ibc.md), +which allows us to publish proofs of the state of one blockchain to another, +and thus to transfer tokens and data between them. diff --git a/docs/guide/basecoin-tool.md b/docs/guide/basecoin-tool.md index 8af94cdee..52f42d832 100644 --- a/docs/guide/basecoin-tool.md +++ b/docs/guide/basecoin-tool.md @@ -140,3 +140,14 @@ You can reset all blockchain data by running: ``` basecoin unsafe_reset_all ``` + + +# Genesis + +Any required plugin initialization should be constructed using `SetOption` on genesis. +When starting a new chain for the first time, `SetOption` will be called for each item the genesis file. +Within genesis.json file entries are made in the format: `"