diff --git a/docs/basecoin/extensions.rst b/docs/basecoin/extensions.rst new file mode 100644 index 0000000000..f88f5b427e --- /dev/null +++ b/docs/basecoin/extensions.rst @@ -0,0 +1,215 @@ +Basecoin Extensions +=================== + +TODO: re-write for extensions + +In the `previous guide `__, we saw how to use the +``basecoin`` tool to start a blockchain and the ``basecli`` tools to +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 tools to use another transaction type, the +``AppTx``, so we can send data to a custom plugin. In this example we +explore a simple plugin named ``counter``. + +Example Plugin +-------------- + +The design of the ``basecoin`` tool makes it easy to extend for custom +functionality. The Counter plugin is bundled with basecoin, so if you +have already `installed basecoin `__ and run +``make install`` then you should be able to run a full node with +``counter`` and the a light-client ``countercli`` from terminal. The +Counter plugin is just like the ``basecoin`` tool. They both use the +same library of commands, including one for signing and broadcasting +``SendTx``. + +Counter transactions take two custom inputs, a boolean argument named +``valid``, and a coin amount named ``countfee``. The transaction is only +accepted if both ``valid`` is set to true and the transaction input +coins is greater than ``countfee`` that the user provides. + +A new blockchain can be initialized and started just like in the +`previous guide `__: + +.. code:: shelldown[0] + + # WARNING: this wipes out data - but counter is only for demos... + rm -rf ~/.counter + countercli reset_all + + countercli keys new cool + countercli keys new friend + + counter init $(countercli keys get cool | awk '{print $2}') + + counter start + +The default files are stored in ``~/.counter``. In another window we can +initialize the light-client and send a transaction: + +.. code:: shelldown[1] + + countercli init --node=tcp://localhost:46657 --genesis=$HOME/.counter/genesis.json + + YOU=$(countercli keys get friend | awk '{print $2}') + countercli tx send --name=cool --amount=1000mycoin --to=$YOU --sequence=1 + +But the Counter has an additional command, ``countercli tx counter``, +which crafts an ``AppTx`` specifically for this plugin: + +.. code:: shelldown[2] + + countercli tx counter --name cool + countercli tx counter --name cool --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: + +.. code:: shelldown[3] + + countercli query counter + +Tada! We can now see that our custom counter plugin transactions went +through. You should see a Counter value of 1 representing the number of +valid transactions. If we send another transaction, and then query +again, we will see the value increment. Note that we need the sequence +number here to send the coins (it didn't increment when we just pinged +the counter) + +.. code:: shelldown[4] + + countercli tx counter --name cool --countfee=2mycoin --sequence=2 --valid + countercli query counter + +The Counter value should be 2, because we sent a second valid +transaction. And this time, since we sent a countfee (which must be less +than or equal to the total amount sent with the tx), it stores the +``TotalFees`` on the counter as well. + +Keep it mind that, just like with ``basecli``, the ``countercli`` +verifies a proof that the query response is correct and up-to-date. + +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. + +.. code:: 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: + +.. code:: 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 `__. + +Implement your own +------------------ + +To implement your own plugin and tooling, make a copy of +``docs/guide/counter``, 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 ``cmd/counter/main.go``, which drives the program. It can +be left alone, but you should change any occurrences of ``counter`` to +whatever your plugin tool is going to be called. You must also register +your plugin(s) with the basecoin app with ``RegisterStartPlugin``. + +The light-client is located in ``cmd/countercli/main.go`` and allows for +transaction and query commands. This file can also be left mostly alone +besides replacing the application name and adding references to new +plugin commands. + +Next is the custom commands in ``cmd/countercli/commands/``. These files +are where we extend the tool with any new commands and flags we need to +send transactions or queries to our plugin. You define custom ``tx`` and +``query`` subcommands, which are registered in ``main.go`` (avoiding +``init()`` auto-registration, for less magic and more control in the +main executable). + +Finally is ``plugins/counter/counter.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 ``CounterTx``, 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 `__. + +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 `__, which allows us +to publish proofs of the state of one blockchain to another, and thus to +transfer tokens and data between them.