From 87d371f32e0bb695bb5b400f35733589a62547b4 Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Mon, 7 May 2018 16:01:58 -0400 Subject: [PATCH 01/21] test --- test.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 test.txt diff --git a/test.txt b/test.txt new file mode 100644 index 0000000000..4e44cf3e9f --- /dev/null +++ b/test.txt @@ -0,0 +1 @@ +test fork \ No newline at end of file From cba8d0082e9cfbd459723445a1285026c840cf0c Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Mon, 21 May 2018 00:18:43 -0300 Subject: [PATCH 02/21] instructions to launch basecoin and do account tx's --- examples/examples.md | 155 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 examples/examples.md diff --git a/examples/examples.md b/examples/examples.md new file mode 100644 index 0000000000..f755084710 --- /dev/null +++ b/examples/examples.md @@ -0,0 +1,155 @@ +# Basecoin Example +=============== + +Here we explain how to get started with a basic Basecoin blockchain, how +to send transactions between accounts using the ``basecli`` tool, and +what is happening under the hood. + +## Setup and Install +------- + +You will need to have go installed on your computer. Please refer to the [cosmos testnet tutorial](https://cosmos.network/validators/tutorial), which will always have the most updated instructions on how to get setup with go and the cosmos repository. + +Once you have go installed, run the command: + +``` +go get github.com/cosmos/cosmos-sdk +``` + +There will be an error stating `can't load package: package github.com/cosmos/cosmos-sdk: no Go files`, however you can ignore this error, it doesn't affect us. Now change directories to: + +`cd $GOPATH/src/github.com/cosmos/cosmos-sdk` + +And run : + +``` +make get_tools // run $ make update_tools if already installed +make get_vendor_deps +make install_examples +``` +In this case we run `make install_examples`, which creates binaries for `basecli` and `basecoind`. + +##Using basecli and basecoind + +Check the versions by running: + +``` +basecli version +basecoind version +``` + +They should read something like `0.17.1-5d18d5f`, but the versions will be constantly updating so don't worry if your version is higher that 0.17.1. + +Note that you can always check help in the terminal by running `basecli -h` or `basecoind -h`. It is good to check these out if you are stuck, because updates to the code base might slighty change the commands, and you might find the correct command in there. + +Let's start by initializing the basecoind daemon. Run the command + +`basecoind init` + +And you should see something like this: + +``` +{ + "chain_id": "test-chain-z77iHG", + "node_id": "e14c5056212b5736e201dd1d64c89246f3288129", + "app_message": { + "secret": "pluck life bracket worry guilt wink upgrade olive tilt output reform census member trouble around abandon" + } +} +``` + +This creates the ~/.basecoind folder, which has config.toml, genesis.json, node_key.json, priv_validator.json. Take some time to review what is contained in these files if you want to understand what is going on at a deeper level. + + +# Generating keys + +The next thing we'll need to do is add the key from priv_validator.json to the gaiacli key manager. For this we need a 16 word seed and a password. You can also get the 16 word seed from the output seen above, under `"secret"`. Then run the command: + +`basecli keys add alice --recover` + +Which will give you three prompts: + +Enter a passphrase for your key: +Repeat the passphrase: +Enter your recovery seed phrase: + +NAME: ADDRESS: PUBKEY: +alice 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD 1624DE62201D47E63694448665F5D0217EA8458177728C91C373047A42BD3C0FB78BD0BFA7 +bob 29D721F054537C91F618A0FDBF770DA51EF8C48D 1624DE6220F54B2A2CA9EB4EE30DE23A73D15902E087C09CC5616456DDDD3814769E2E0A16 +charlie 2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E 1624DE6220F8C9FB8B07855FD94126F88A155BD6EB973509AE5595EFDE1AF05B4964836A53 + +Creating you first locally saved key creates the ~/.basecli folder which holds the keys you are storing. Now that you have the key for alice, you can start up the blockchain by running + +`basecoind start` + +You should see blocks start getting created at a fast rate, with a lot of output in the terminal. + +Next we need to make some more keys so we can send them some tokens. Open a new terminal, and run the following commands, to make two new accounts, and give each account a password you can remember: + +`basecli keys add bob` +`basecli keys add charlie` + +You can see your keys with the command: + +`basecli keys list` + +You should now see alice, bob and charlie's account all show up. + +# Send transactions + +Lets send bob and charlie some tokens. First, lets query alice's account so we can see what kind of tokens she has: + +`basecli account 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` + +Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alices address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search the bob or charlies address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some! + +The following command will send coins from alice, to bob: + +`basecli send --name=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D --sequence=0 --chain-id=test-chain-AE4XQo` + +Where +- name is the name you gave your key +- `mycoin` is the name of the token for this basecoin demo, initialized in the genesis.json file +- sequence is a tally of how many transactions have been made by this account. Sicne this is the first tx on this account, it is 0 +- chain-id is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/gensis.json` + +Now if we check bobs account, it should have ``10000`` 'mycoin' : + +`basecli account 29D721F054537C91F618A0FDBF770DA51EF8C48D` + +Now lets send some from bob to charlie + +`basecli send --name=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E --sequence=0 --chain-id=test-chain-AE4XQo` + +Note how we use the ``--name`` flag to select a different account to send from. + +Lets now try to send from bob back to alice: + +`basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD --sequence=1 --chain-id=test-chain-AE4XQo` + +Notice that the sequence is now 1, since we have already recorded bobs 1st transaction as sequnce 0. Also note the ``hash`` value in the response - this is the hash of the transaction. We can query for the transaction by this hash: + +`basecli tx ` + +It will return the details of the transaction hash, such as how many coins were send and to which address. + +That is the basic implementation of basecoin! + + +## Clean up the basecoind and basecli data + +**WARNING:** Running these commands will wipe out any existing +information in both the ``~/.basecli`` and ``~/.basecoind`` directories, +including private keys. + +To remove all the files created and refresh your environment (e.g., if +starting this tutorial again or trying something new), the following +commands are run: + +``` +basecoind unsafe_reset_all +rm -rf ~/.basecoind +rm -rf ~/.basecli +``` + + From c5983df57a60a4366fd964e9f9291569174f8fbe Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Mon, 21 May 2018 00:22:05 -0300 Subject: [PATCH 03/21] deleted a test file that isnt needed --- test.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 test.txt diff --git a/test.txt b/test.txt deleted file mode 100644 index 4e44cf3e9f..0000000000 --- a/test.txt +++ /dev/null @@ -1 +0,0 @@ -test fork \ No newline at end of file From 2c01805a1b9eb637e8eddcd2ba45d072d0e9f47b Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Mon, 21 May 2018 00:28:31 -0300 Subject: [PATCH 04/21] markdown formatting fixes --- examples/examples.md | 64 ++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/examples/examples.md b/examples/examples.md index f755084710..53610855a7 100644 --- a/examples/examples.md +++ b/examples/examples.md @@ -1,12 +1,10 @@ # Basecoin Example -=============== Here we explain how to get started with a basic Basecoin blockchain, how to send transactions between accounts using the ``basecli`` tool, and what is happening under the hood. ## Setup and Install -------- You will need to have go installed on your computer. Please refer to the [cosmos testnet tutorial](https://cosmos.network/validators/tutorial), which will always have the most updated instructions on how to get setup with go and the cosmos repository. @@ -18,18 +16,20 @@ go get github.com/cosmos/cosmos-sdk There will be an error stating `can't load package: package github.com/cosmos/cosmos-sdk: no Go files`, however you can ignore this error, it doesn't affect us. Now change directories to: -`cd $GOPATH/src/github.com/cosmos/cosmos-sdk` +``` +cd $GOPATH/src/github.com/cosmos/cosmos-sdk +``` And run : ``` -make get_tools // run $ make update_tools if already installed +make get_tools // run make update_tools if you already had it installed make get_vendor_deps make install_examples ``` In this case we run `make install_examples`, which creates binaries for `basecli` and `basecoind`. -##Using basecli and basecoind +## Using basecli and basecoind Check the versions by running: @@ -44,7 +44,9 @@ Note that you can always check help in the terminal by running `basecli -h` or ` Let's start by initializing the basecoind daemon. Run the command -`basecoind init` +``` +basecoind init +``` And you should see something like this: @@ -58,14 +60,16 @@ And you should see something like this: } ``` -This creates the ~/.basecoind folder, which has config.toml, genesis.json, node_key.json, priv_validator.json. Take some time to review what is contained in these files if you want to understand what is going on at a deeper level. +This creates the `~/.basecoind folder`, which has config.toml, genesis.json, node_key.json, priv_validator.json. Take some time to review what is contained in these files if you want to understand what is going on at a deeper level. -# Generating keys +## Generating keys The next thing we'll need to do is add the key from priv_validator.json to the gaiacli key manager. For this we need a 16 word seed and a password. You can also get the 16 word seed from the output seen above, under `"secret"`. Then run the command: -`basecli keys add alice --recover` +``` +basecli keys add alice --recover +``` Which will give you three prompts: @@ -73,39 +77,51 @@ Enter a passphrase for your key: Repeat the passphrase: Enter your recovery seed phrase: +``` NAME: ADDRESS: PUBKEY: alice 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD 1624DE62201D47E63694448665F5D0217EA8458177728C91C373047A42BD3C0FB78BD0BFA7 bob 29D721F054537C91F618A0FDBF770DA51EF8C48D 1624DE6220F54B2A2CA9EB4EE30DE23A73D15902E087C09CC5616456DDDD3814769E2E0A16 charlie 2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E 1624DE6220F8C9FB8B07855FD94126F88A155BD6EB973509AE5595EFDE1AF05B4964836A53 +``` Creating you first locally saved key creates the ~/.basecli folder which holds the keys you are storing. Now that you have the key for alice, you can start up the blockchain by running -`basecoind start` +``` +basecoind start +``` You should see blocks start getting created at a fast rate, with a lot of output in the terminal. Next we need to make some more keys so we can send them some tokens. Open a new terminal, and run the following commands, to make two new accounts, and give each account a password you can remember: -`basecli keys add bob` -`basecli keys add charlie` +``` +basecli keys add bob +basecli keys add charlie +``` You can see your keys with the command: -`basecli keys list` +``` +basecli keys list +``` You should now see alice, bob and charlie's account all show up. -# Send transactions +## Send transactions Lets send bob and charlie some tokens. First, lets query alice's account so we can see what kind of tokens she has: -`basecli account 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` +``` +basecli account 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD +``` Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alices address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search the bob or charlies address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some! The following command will send coins from alice, to bob: -`basecli send --name=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D --sequence=0 --chain-id=test-chain-AE4XQo` +``` +basecli send --name=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D --sequence=0 --chain-id=test-chain-AE4XQo +``` Where - name is the name you gave your key @@ -115,21 +131,29 @@ Where Now if we check bobs account, it should have ``10000`` 'mycoin' : -`basecli account 29D721F054537C91F618A0FDBF770DA51EF8C48D` +``` +basecli account 29D721F054537C91F618A0FDBF770DA51EF8C48D +``` Now lets send some from bob to charlie -`basecli send --name=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E --sequence=0 --chain-id=test-chain-AE4XQo` +``` +basecli send --name=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E --sequence=0 --chain-id=test-chain-AE4XQo +``` Note how we use the ``--name`` flag to select a different account to send from. Lets now try to send from bob back to alice: -`basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD --sequence=1 --chain-id=test-chain-AE4XQo` +``` +basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD --sequence=1 --chain-id=test-chain-AE4XQo +``` Notice that the sequence is now 1, since we have already recorded bobs 1st transaction as sequnce 0. Also note the ``hash`` value in the response - this is the hash of the transaction. We can query for the transaction by this hash: -`basecli tx ` +``` +basecli tx +``` It will return the details of the transaction hash, such as how many coins were send and to which address. From 1e097889cbc9a22b7e6b3d507cf4e87da2cd4451 Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Mon, 21 May 2018 00:31:22 -0300 Subject: [PATCH 05/21] markdown formatting fixes --- examples/examples.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/examples/examples.md b/examples/examples.md index 53610855a7..ff998450f8 100644 --- a/examples/examples.md +++ b/examples/examples.md @@ -79,9 +79,9 @@ Enter your recovery seed phrase: ``` NAME: ADDRESS: PUBKEY: -alice 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD 1624DE62201D47E63694448665F5D0217EA8458177728C91C373047A42BD3C0FB78BD0BFA7 -bob 29D721F054537C91F618A0FDBF770DA51EF8C48D 1624DE6220F54B2A2CA9EB4EE30DE23A73D15902E087C09CC5616456DDDD3814769E2E0A16 -charlie 2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E 1624DE6220F8C9FB8B07855FD94126F88A155BD6EB973509AE5595EFDE1AF05B4964836A53 +alice 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD 1624DE62201D47E63694448665F5D0217EA8458177728C91C373047A42BD3C0FB78BD0BFA7 +bob 29D721F054537C91F618A0FDBF770DA51EF8C48D 1624DE6220F54B2A2CA9EB4EE30DE23A73D15902E087C09CC5616456DDDD3814769E2E0A16 +charlie 2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E 1624DE6220F8C9FB8B07855FD94126F88A155BD6EB973509AE5595EFDE1AF05B4964836A53 ``` Creating you first locally saved key creates the ~/.basecli folder which holds the keys you are storing. Now that you have the key for alice, you can start up the blockchain by running @@ -120,16 +120,17 @@ Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alices address we got from r The following command will send coins from alice, to bob: ``` -basecli send --name=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D --sequence=0 --chain-id=test-chain-AE4XQo +basecli send --name=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D +--sequence=0 --chain-id=test-chain-AE4XQo ``` -Where +Flag Descriptions: - name is the name you gave your key - `mycoin` is the name of the token for this basecoin demo, initialized in the genesis.json file - sequence is a tally of how many transactions have been made by this account. Sicne this is the first tx on this account, it is 0 - chain-id is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/gensis.json` -Now if we check bobs account, it should have ``10000`` 'mycoin' : +Now if we check bobs account, it should have `10000 mycoin` : ``` basecli account 29D721F054537C91F618A0FDBF770DA51EF8C48D @@ -138,7 +139,8 @@ basecli account 29D721F054537C91F618A0FDBF770DA51EF8C48D Now lets send some from bob to charlie ``` -basecli send --name=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E --sequence=0 --chain-id=test-chain-AE4XQo +basecli send --name=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E +--sequence=0 --chain-id=test-chain-AE4XQo ``` Note how we use the ``--name`` flag to select a different account to send from. From 1fdb65169a0389e153b52d623fe86f015cb8ada8 Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Tue, 22 May 2018 21:03:19 -0300 Subject: [PATCH 06/21] added updated explaination from old docs --- examples/examples.md | 164 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 150 insertions(+), 14 deletions(-) diff --git a/examples/examples.md b/examples/examples.md index ff998450f8..804636e25b 100644 --- a/examples/examples.md +++ b/examples/examples.md @@ -27,7 +27,7 @@ make get_tools // run make update_tools if you already had it installed make get_vendor_deps make install_examples ``` -In this case we run `make install_examples`, which creates binaries for `basecli` and `basecoind`. +Then run `make install_examples`, which creates binaries for `basecli` and `basecoind`. You can look at the Makefile if you want to see the details on what these make commands are doing. ## Using basecli and basecoind @@ -65,7 +65,7 @@ This creates the `~/.basecoind folder`, which has config.toml, genesis.json, nod ## Generating keys -The next thing we'll need to do is add the key from priv_validator.json to the gaiacli key manager. For this we need a 16 word seed and a password. You can also get the 16 word seed from the output seen above, under `"secret"`. Then run the command: +The next thing we'll need to do is add the key from priv_validator.json to the gaiacli key manager. For this we need the 16 word seed that represents the private key, and a password. You can also get the 16 word seed from the output seen above, under `"secret"`. Then run the command: ``` basecli keys add alice --recover @@ -73,18 +73,13 @@ basecli keys add alice --recover Which will give you three prompts: +``` Enter a passphrase for your key: Repeat the passphrase: Enter your recovery seed phrase: - -``` -NAME: ADDRESS: PUBKEY: -alice 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD 1624DE62201D47E63694448665F5D0217EA8458177728C91C373047A42BD3C0FB78BD0BFA7 -bob 29D721F054537C91F618A0FDBF770DA51EF8C48D 1624DE6220F54B2A2CA9EB4EE30DE23A73D15902E087C09CC5616456DDDD3814769E2E0A16 -charlie 2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E 1624DE6220F8C9FB8B07855FD94126F88A155BD6EB973509AE5595EFDE1AF05B4964836A53 ``` -Creating you first locally saved key creates the ~/.basecli folder which holds the keys you are storing. Now that you have the key for alice, you can start up the blockchain by running +You just created your first locally stored key, under the name alice, and this account is linked to the private key that is running the basecoind validator node. Once you do this, the ~/.basecli folder is created, which will hold all keys you are storing. Now that you have the key for alice, you can start up the blockchain by running ``` basecoind start @@ -107,6 +102,14 @@ basecli keys list You should now see alice, bob and charlie's account all show up. +``` +NAME: ADDRESS: PUBKEY: +alice 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD 1624DE62201D47E63694448665F5D0217EA8458177728C91C373047A42BD3C0FB78BD0BFA7 +bob 29D721F054537C91F618A0FDBF770DA51EF8C48D 1624DE6220F54B2A2CA9EB4EE30DE23A73D15902E087C09CC5616456DDDD3814769E2E0A16 +charlie 2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E 1624DE6220F8C9FB8B07855FD94126F88A155BD6EB973509AE5595EFDE1AF05B4964836A53 +``` + + ## Send transactions Lets send bob and charlie some tokens. First, lets query alice's account so we can see what kind of tokens she has: @@ -115,7 +118,7 @@ Lets send bob and charlie some tokens. First, lets query alice's account so we c basecli account 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD ``` -Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alices address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search the bob or charlies address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some! +Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alices address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search for bob's or charlie's address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some! The following command will send coins from alice, to bob: @@ -130,13 +133,13 @@ Flag Descriptions: - sequence is a tally of how many transactions have been made by this account. Sicne this is the first tx on this account, it is 0 - chain-id is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/gensis.json` -Now if we check bobs account, it should have `10000 mycoin` : +Now if we check bobs account, it should have `10000 mycoin`. You can do so by running : ``` basecli account 29D721F054537C91F618A0FDBF770DA51EF8C48D ``` -Now lets send some from bob to charlie +Now lets send some from bob to charlie. Make sure you send less than bob has, otherwise the transaction will fail: ``` basecli send --name=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E @@ -151,13 +154,13 @@ Lets now try to send from bob back to alice: basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD --sequence=1 --chain-id=test-chain-AE4XQo ``` -Notice that the sequence is now 1, since we have already recorded bobs 1st transaction as sequnce 0. Also note the ``hash`` value in the response - this is the hash of the transaction. We can query for the transaction by this hash: +Notice that the sequence is now 1, since we have already recorded bobs 1st transaction as sequnce 0. Also note the ``hash`` value in the response in the terminal - this is the hash of the transaction. We can query for the transaction with this command: ``` basecli tx ``` -It will return the details of the transaction hash, such as how many coins were send and to which address. +It will return the details of the transaction hash, such as how many coins were send and to which address, and on what block it occured That is the basic implementation of basecoin! @@ -178,4 +181,137 @@ rm -rf ~/.basecoind rm -rf ~/.basecli ``` +# Technical Details on how Basecoin Works + +This section describes some of the more technical aspects for what is going on under the hood of Basecoin. + +## Proof + +Even if you don't see it in the UI, the result of every query comes with +a proof. This is a Merkle proof that the result of the query is actually +contained in the state. And the state's Merkle root is contained in a +recent block header. Behind the scenes, ``basecli`` will not only +verify that this state matches the header, but also that the header is +properly signed by the known validator set. It will even update the +validator set as needed, so long as there have not been major changes +and it is secure to do so. So, if you wonder why the query may take a +second... there is a lot of work going on in the background to make sure +even a lying full node can't trick your client. + +## Accounts and Transactions + +For a better understanding of how to further use the tools, it helps to +understand the underlying data structures. + +### Accounts + +The Basecoin state consists entirely of a set of accounts. Each account +contains an address, a 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). + +``` + type BaseAccount struct { + Address sdk.Address `json:"address"` + Coins sdk.Coins `json:"coins"` + PubKey crypto.PubKey `json:"public_key"` + Sequence int64 `json:"sequence"` + } +``` + +You can also add more fields to accounts, and basecoin actually does so. Basecoin +adds a Name field in order to show how easily the base account structure can be +modified to suit any applications needs. + +``` + type AppAccount struct { + auth.BaseAccount + Name string `json:"name"` + } +``` + +Within accounts, coin balances are stored. Basecoin is a multi-asset cryptocurrency, so each account can have many +different kinds of tokens, which are held in an array. + +``` + type Coins []Coin + + type Coin struct { + Denom string `json:"denom"` + Amount int64 `json:"amount"` + } +``` + +If you want to add more coins to a blockchain, you can do so manually in +the ``~/.basecoin/genesis.json`` before you start the blockchain for the +first time. + +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 `__. The Merkle tree +used in Basecoin is a balanced, binary search tree, which we call an +`IAVL tree `__. + +### Transactions + +Basecoin defines a 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: +``` + 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 Basecoin, 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... so this version of Basecoin does +not actually fully implement fees and gas, but it still allows us +to send transactions between accounts. + +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. From 450f0b6822c948bb6ac023f9a0d9f3dd9724f577 Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Tue, 22 May 2018 21:44:50 -0300 Subject: [PATCH 07/21] fixing display --- examples/examples.md | 68 ++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/examples/examples.md b/examples/examples.md index 804636e25b..6af50fcfa2 100644 --- a/examples/examples.md +++ b/examples/examples.md @@ -157,7 +157,7 @@ basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A0 Notice that the sequence is now 1, since we have already recorded bobs 1st transaction as sequnce 0. Also note the ``hash`` value in the response in the terminal - this is the hash of the transaction. We can query for the transaction with this command: ``` -basecli tx +basecli tx ``` It will return the details of the transaction hash, such as how many coins were send and to which address, and on what block it occured @@ -181,7 +181,7 @@ rm -rf ~/.basecoind rm -rf ~/.basecli ``` -# Technical Details on how Basecoin Works +## Technical Details on how Basecoin Works This section describes some of the more technical aspects for what is going on under the hood of Basecoin. @@ -212,12 +212,12 @@ type of account was directly inspired by accounts in Ethereum, and is unlike Bitcoin's use of Unspent Transaction Outputs (UTXOs). ``` - type BaseAccount struct { - Address sdk.Address `json:"address"` - Coins sdk.Coins `json:"coins"` - PubKey crypto.PubKey `json:"public_key"` - Sequence int64 `json:"sequence"` - } +type BaseAccount struct { + Address sdk.Address `json:"address"` + Coins sdk.Coins `json:"coins"` + PubKey crypto.PubKey `json:"public_key"` + Sequence int64 `json:"sequence"` +} ``` You can also add more fields to accounts, and basecoin actually does so. Basecoin @@ -225,22 +225,22 @@ adds a Name field in order to show how easily the base account structure can be modified to suit any applications needs. ``` - type AppAccount struct { - auth.BaseAccount - Name string `json:"name"` - } +type AppAccount struct { + auth.BaseAccount + Name string `json:"name"` +} ``` Within accounts, coin balances are stored. Basecoin is a multi-asset cryptocurrency, so each account can have many different kinds of tokens, which are held in an array. ``` - type Coins []Coin +type Coins []Coin - type Coin struct { - Denom string `json:"denom"` - Amount int64 `json:"amount"` - } +type Coin struct { + Denom string `json:"denom"` + Amount int64 `json:"amount"` +} ``` If you want to add more coins to a blockchain, you can do so manually in @@ -264,25 +264,25 @@ 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: ``` - type SendTx struct { - Gas int64 `json:"gas"` - Fee Coin `json:"fee"` - Inputs []TxInput `json:"inputs"` - Outputs []TxOutput `json:"outputs"` - } +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 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"` // - } +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 From 89f787a3dfb01c2e989edfc9d9680357d4bbb2ae Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Tue, 22 May 2018 21:56:07 -0300 Subject: [PATCH 08/21] more display updates --- examples/examples.md | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/examples.md b/examples/examples.md index 6af50fcfa2..b295bea6b2 100644 --- a/examples/examples.md +++ b/examples/examples.md @@ -1,6 +1,6 @@ # Basecoin Example -Here we explain how to get started with a basic Basecoin blockchain, how +Here we explain how to get started with a simple Basecoin blockchain, how to send transactions between accounts using the ``basecli`` tool, and what is happening under the hood. @@ -38,7 +38,7 @@ basecli version basecoind version ``` -They should read something like `0.17.1-5d18d5f`, but the versions will be constantly updating so don't worry if your version is higher that 0.17.1. +They should read something like `0.17.1-5d18d5f`, but the versions will be constantly updating so don't worry if your version is higher that 0.17.1. That's a good thing. Note that you can always check help in the terminal by running `basecli -h` or `basecoind -h`. It is good to check these out if you are stuck, because updates to the code base might slighty change the commands, and you might find the correct command in there. @@ -79,15 +79,15 @@ Repeat the passphrase: Enter your recovery seed phrase: ``` -You just created your first locally stored key, under the name alice, and this account is linked to the private key that is running the basecoind validator node. Once you do this, the ~/.basecli folder is created, which will hold all keys you are storing. Now that you have the key for alice, you can start up the blockchain by running +You just created your first locally stored key, under the name alice, and this account is linked to the private key that is running the basecoind validator node. Once you do this, the ~/.basecli folder is created, which will hold the alice key and any other keys you make. Now that you have the key for alice, you can start up the blockchain by running ``` basecoind start ``` -You should see blocks start getting created at a fast rate, with a lot of output in the terminal. +You should see blocks being created at a fast rate, with a lot of output in the terminal. -Next we need to make some more keys so we can send them some tokens. Open a new terminal, and run the following commands, to make two new accounts, and give each account a password you can remember: +Next we need to make some more keys so we can use the send transaction functionality of basecoin. Open a new terminal, and run the following commands, to make two new accounts, and give each account a password you can remember: ``` basecli keys add bob @@ -105,7 +105,7 @@ You should now see alice, bob and charlie's account all show up. ``` NAME: ADDRESS: PUBKEY: alice 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD 1624DE62201D47E63694448665F5D0217EA8458177728C91C373047A42BD3C0FB78BD0BFA7 -bob 29D721F054537C91F618A0FDBF770DA51EF8C48D 1624DE6220F54B2A2CA9EB4EE30DE23A73D15902E087C09CC5616456DDDD3814769E2E0A16 +bob 29D721F054537C91F618A0FDBF770DA51EF8C48D 1624DE6220F54B2A2CA9EB4EE30DE23A73D15902E087C09CC5616456DDDD3814769E2E0A16 charlie 2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E 1624DE6220F8C9FB8B07855FD94126F88A155BD6EB973509AE5595EFDE1AF05B4964836A53 ``` @@ -128,10 +128,10 @@ basecli send --name=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF77 ``` Flag Descriptions: -- name is the name you gave your key +- `name` is the name you gave your key - `mycoin` is the name of the token for this basecoin demo, initialized in the genesis.json file -- sequence is a tally of how many transactions have been made by this account. Sicne this is the first tx on this account, it is 0 -- chain-id is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/gensis.json` +- `sequence` is a tally of how many transactions have been made by this account. Sicne this is the first tx on this account, it is 0 +- `chain-id` is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/gensis.json` Now if we check bobs account, it should have `10000 mycoin`. You can do so by running : @@ -151,25 +151,28 @@ Note how we use the ``--name`` flag to select a different account to send from. Lets now try to send from bob back to alice: ``` -basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD --sequence=1 --chain-id=test-chain-AE4XQo +basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD +--sequence=1 --chain-id=test-chain-AE4XQo ``` -Notice that the sequence is now 1, since we have already recorded bobs 1st transaction as sequnce 0. Also note the ``hash`` value in the response in the terminal - this is the hash of the transaction. We can query for the transaction with this command: +Notice that the sequence is now 1, since we have already recorded bobs 1st transaction as `sequnce 0`. Also note the ``hash`` value in the response in the terminal - this is the hash of the transaction. We can query for the transaction with this command: ``` basecli tx ``` -It will return the details of the transaction hash, such as how many coins were send and to which address, and on what block it occured +It will return the details of the transaction hash, such as how many coins were send and to which address, and on what block it occured. That is the basic implementation of basecoin! -## Clean up the basecoind and basecli data +## Reset the basecoind blockchain and basecli data **WARNING:** Running these commands will wipe out any existing information in both the ``~/.basecli`` and ``~/.basecoind`` directories, -including private keys. +including private keys. This should be no problem considering that basecoin +is just an example, but it is always good to pay extra attention when +you are removing private keys, in any scenario involving a blockchain. To remove all the files created and refresh your environment (e.g., if starting this tutorial again or trying something new), the following @@ -201,7 +204,7 @@ even a lying full node can't trick your client. ## Accounts and Transactions For a better understanding of how to further use the tools, it helps to -understand the underlying data structures. +understand the underlying data structures, so lets look at accounts and transactions. ### Accounts @@ -222,7 +225,8 @@ type BaseAccount struct { You can also add more fields to accounts, and basecoin actually does so. Basecoin adds a Name field in order to show how easily the base account structure can be -modified to suit any applications needs. +modified to suit any applications needs. It takes the `auth.BaseAccount` we see above, +and extends it with `Name`. ``` type AppAccount struct { From 114c9a2077d2a70fbd560585d2936fe94241b812 Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Tue, 22 May 2018 21:56:43 -0300 Subject: [PATCH 09/21] more display updates --- examples/examples.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/examples.md b/examples/examples.md index b295bea6b2..bfc97893ef 100644 --- a/examples/examples.md +++ b/examples/examples.md @@ -216,7 +216,7 @@ unlike Bitcoin's use of Unspent Transaction Outputs (UTXOs). ``` type BaseAccount struct { - Address sdk.Address `json:"address"` + Address sdk.Address `json:"address"` Coins sdk.Coins `json:"coins"` PubKey crypto.PubKey `json:"public_key"` Sequence int64 `json:"sequence"` From 16e18b7e9680667105f422a455300bae5c002eda Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Wed, 23 May 2018 09:43:17 -0300 Subject: [PATCH 10/21] fixed small typos --- examples/examples.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/examples.md b/examples/examples.md index bfc97893ef..7d8665ca62 100644 --- a/examples/examples.md +++ b/examples/examples.md @@ -1,6 +1,6 @@ # Basecoin Example -Here we explain how to get started with a simple Basecoin blockchain, how +Here we explain how to get started with a basic Basecoin blockchain, how to send transactions between accounts using the ``basecli`` tool, and what is happening under the hood. @@ -103,7 +103,7 @@ basecli keys list You should now see alice, bob and charlie's account all show up. ``` -NAME: ADDRESS: PUBKEY: +NAME: ADDRESS: PUBKEY: alice 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD 1624DE62201D47E63694448665F5D0217EA8458177728C91C373047A42BD3C0FB78BD0BFA7 bob 29D721F054537C91F618A0FDBF770DA51EF8C48D 1624DE6220F54B2A2CA9EB4EE30DE23A73D15902E087C09CC5616456DDDD3814769E2E0A16 charlie 2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E 1624DE6220F8C9FB8B07855FD94126F88A155BD6EB973509AE5595EFDE1AF05B4964836A53 @@ -118,7 +118,7 @@ Lets send bob and charlie some tokens. First, lets query alice's account so we c basecli account 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD ``` -Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alices address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search for bob's or charlie's address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some! +Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alice's address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search for bob's or charlie's address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some! The following command will send coins from alice, to bob: @@ -130,7 +130,7 @@ basecli send --name=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF77 Flag Descriptions: - `name` is the name you gave your key - `mycoin` is the name of the token for this basecoin demo, initialized in the genesis.json file -- `sequence` is a tally of how many transactions have been made by this account. Sicne this is the first tx on this account, it is 0 +- `sequence` is a tally of how many transactions have been made by this account. Since this is the first tx on this account, it is 0 - `chain-id` is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/gensis.json` Now if we check bobs account, it should have `10000 mycoin`. You can do so by running : @@ -155,7 +155,7 @@ basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A0 --sequence=1 --chain-id=test-chain-AE4XQo ``` -Notice that the sequence is now 1, since we have already recorded bobs 1st transaction as `sequnce 0`. Also note the ``hash`` value in the response in the terminal - this is the hash of the transaction. We can query for the transaction with this command: +Notice that the sequence is now 1, since we have already recorded bobs 1st transaction as `sequence 0`. Also note the ``hash`` value in the response in the terminal - this is the hash of the transaction. We can query for the transaction with this command: ``` basecli tx From 3055d939edd968deee8a0c2ad33fef8664e8bd1d Mon Sep 17 00:00:00 2001 From: sunnya97 Date: Wed, 23 May 2018 19:26:54 -0700 Subject: [PATCH 11/21] in progress --- baseapp/baseapp.go | 3 +- client/context/helpers.go | 9 +- client/context/types.go | 6 +- client/tx/query.go | 3 +- cmd/gaia/app/app.go | 13 +- cmd/gaia/app/genesis.go | 11 +- types/account.go | 29 ----- types/handler.go | 3 - types/signature.go | 10 -- types/tx_msg.go | 117 ----------------- x/auth/account.go | 25 ++++ x/auth/ante.go | 30 ++--- x/auth/client/cli/account.go | 7 +- x/auth/context.go | 8 +- x/auth/mapper.go | 30 +++-- x/auth/stdtx.go | 131 ++++++++++++++++++++ x/auth/wire.go | 12 -- x/bank/keeper.go | 27 ++-- x/{auth => baseaccount}/baseaccount.go | 9 +- x/{auth => baseaccount}/baseaccount_test.go | 2 +- x/{auth => baseaccount}/handler.go | 13 +- x/{auth => baseaccount}/msgs.go | 7 +- x/{auth => baseaccount}/msgs_test.go | 2 +- x/baseaccount/wire.go | 14 +++ x/stake/test_common.go | 13 +- 25 files changed, 270 insertions(+), 264 deletions(-) delete mode 100644 types/signature.go create mode 100644 x/auth/account.go create mode 100644 x/auth/stdtx.go delete mode 100644 x/auth/wire.go rename x/{auth => baseaccount}/baseaccount.go (90%) rename x/{auth => baseaccount}/baseaccount_test.go (99%) rename x/{auth => baseaccount}/handler.go (58%) rename x/{auth => baseaccount}/msgs.go (87%) rename x/{auth => baseaccount}/msgs_test.go (97%) create mode 100644 x/baseaccount/wire.go diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index ef3bbc3c79..4ce8a05d9b 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -15,6 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) // Key to store the header in the DB itself. @@ -125,7 +126,7 @@ func (app *BaseApp) SetTxDecoder(txDecoder sdk.TxDecoder) { // default custom logic for transaction decoding func defaultTxDecoder(cdc *wire.Codec) sdk.TxDecoder { return func(txBytes []byte) (sdk.Tx, sdk.Error) { - var tx = sdk.StdTx{} + var tx = auth.StdTx{} if len(txBytes) == 0 { return nil, sdk.ErrTxDecode("txBytes are empty") diff --git a/client/context/helpers.go b/client/context/helpers.go index 562bde9b4c..f4686befde 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" cmn "github.com/tendermint/tmlibs/common" @@ -109,11 +110,11 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w return nil, errors.Errorf("Chain ID required but not specified") } sequence := ctx.Sequence - signMsg := sdk.StdSignMsg{ + signMsg := auth.StdSignMsg{ ChainID: chainID, Sequences: []int64{sequence}, Msg: msg, - Fee: sdk.NewStdFee(10000, sdk.Coin{}), // TODO run simulate to estimate gas? + Fee: auth.NewStdFee(10000, sdk.Coin{}), // TODO run simulate to estimate gas? } keybase, err := keys.GetKeyBase() @@ -128,14 +129,14 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w if err != nil { return nil, err } - sigs := []sdk.StdSignature{{ + sigs := []auth.StdSignature{{ PubKey: pubkey, Signature: sig, Sequence: sequence, }} // marshal bytes - tx := sdk.NewStdTx(signMsg.Msg, signMsg.Fee, sigs) + tx := auth.NewStdTx(signMsg.Msg, signMsg.Fee, sigs) return cdc.MarshalBinary(tx) } diff --git a/client/context/types.go b/client/context/types.go index e580027d67..da15b32936 100644 --- a/client/context/types.go +++ b/client/context/types.go @@ -3,7 +3,7 @@ package context import ( rpcclient "github.com/tendermint/tendermint/rpc/client" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) // typical context created in sdk modules for transactions/queries @@ -15,7 +15,7 @@ type CoreContext struct { FromAddressName string Sequence int64 Client rpcclient.Client - Decoder sdk.AccountDecoder + Decoder auth.AccountDecoder AccountStore string } @@ -63,7 +63,7 @@ func (c CoreContext) WithClient(client rpcclient.Client) CoreContext { } // WithDecoder - return a copy of the context with an updated Decoder -func (c CoreContext) WithDecoder(decoder sdk.AccountDecoder) CoreContext { +func (c CoreContext) WithDecoder(decoder auth.AccountDecoder) CoreContext { c.Decoder = decoder return c } diff --git a/client/tx/query.go b/client/tx/query.go index 2078b78831..7673dd38db 100644 --- a/client/tx/query.go +++ b/client/tx/query.go @@ -17,6 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) // Get the default command for a tx query @@ -95,7 +96,7 @@ type txInfo struct { } func parseTx(cdc *wire.Codec, txBytes []byte) (sdk.Tx, error) { - var tx sdk.StdTx + var tx auth.StdTx err := cdc.UnmarshalBinary(txBytes, &tx) if err != nil { return nil, err diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 5ff532bffa..df4429ee25 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/baseaccount" "github.com/cosmos/cosmos-sdk/x/ibc" "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -40,7 +41,7 @@ type GaiaApp struct { keyStake *sdk.KVStoreKey // Manage getting and setting accounts - accountMapper sdk.AccountMapper + accountMapper auth.AccountMapper coinKeeper bank.Keeper ibcMapper ibc.Mapper stakeKeeper stake.Keeper @@ -62,8 +63,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { // define the accountMapper app.accountMapper = auth.NewAccountMapper( app.cdc, - app.keyAccount, // target store - &auth.BaseAccount{}, // prototype + app.keyAccount, // target store + &baseaccount.BaseAccount{}, // prototype ) // add handlers @@ -81,7 +82,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { app.SetInitChainer(app.initChainer) app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper)) app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, stake.FeeHandler)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper)) err := app.LoadLatestVersion(app.keyMain) if err != nil { cmn.Exit(err.Error()) @@ -96,7 +97,7 @@ func MakeCodec() *wire.Codec { ibc.RegisterWire(cdc) bank.RegisterWire(cdc) stake.RegisterWire(cdc) - auth.RegisterWire(cdc) + baseaccount.RegisterWire(cdc) sdk.RegisterWire(cdc) wire.RegisterCrypto(cdc) return cdc @@ -131,7 +132,7 @@ func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) { // iterate to get the accounts accounts := []GenesisAccount{} - appendAccount := func(acc sdk.Account) (stop bool) { + appendAccount := func(acc auth.Account) (stop bool) { account := NewGenesisAccountI(acc) accounts = append(accounts, account) return false diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 7cb7564dd3..fb02a19ef4 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -13,6 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/baseaccount" "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -28,14 +29,14 @@ type GenesisAccount struct { Coins sdk.Coins `json:"coins"` } -func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount { +func NewGenesisAccount(acc *baseaccount.BaseAccount) GenesisAccount { return GenesisAccount{ Address: acc.Address, Coins: acc.Coins, } } -func NewGenesisAccountI(acc sdk.Account) GenesisAccount { +func NewGenesisAccountI(acc auth.Account) GenesisAccount { return GenesisAccount{ Address: acc.GetAddress(), Coins: acc.GetCoins(), @@ -43,8 +44,8 @@ func NewGenesisAccountI(acc sdk.Account) GenesisAccount { } // convert GenesisAccount to auth.BaseAccount -func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { - return &auth.BaseAccount{ +func (ga *GenesisAccount) ToAccount() (acc *baseaccount.BaseAccount) { + return &baseaccount.BaseAccount{ Address: ga.Address, Coins: ga.Coins.Sort(), } @@ -148,7 +149,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso } // create the genesis account, give'm few steaks and a buncha token with there name - accAuth := auth.NewBaseAccountWithAddress(genTx.Address) + accAuth := baseaccount.NewBaseAccountWithAddress(genTx.Address) accAuth.Coins = sdk.Coins{ {genTx.Name + "Token", 1000}, {"steak", freeFermionsAcc}, diff --git a/types/account.go b/types/account.go index 74cd87f38c..be8b90a1cd 100644 --- a/types/account.go +++ b/types/account.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "errors" - crypto "github.com/tendermint/go-crypto" cmn "github.com/tendermint/tmlibs/common" ) @@ -22,31 +21,3 @@ func GetAddress(address string) (addr Address, err error) { } return Address(bz), nil } - -// Account is a standard account using a sequence number for replay protection -// and a pubkey for authentication. -type Account interface { - GetAddress() Address - SetAddress(Address) error // errors if already set. - - GetPubKey() crypto.PubKey // can return nil. - SetPubKey(crypto.PubKey) error - - GetSequence() int64 - SetSequence(int64) error - - GetCoins() Coins - SetCoins(Coins) error -} - -// AccountMapper stores and retrieves accounts from stores -// retrieved from the context. -type AccountMapper interface { - NewAccountWithAddress(ctx Context, addr Address) Account - GetAccount(ctx Context, addr Address) Account - SetAccount(ctx Context, acc Account) - IterateAccounts(ctx Context, process func(Account) (stop bool)) -} - -// AccountDecoder unmarshals account bytes -type AccountDecoder func(accountBytes []byte) (Account, error) diff --git a/types/handler.go b/types/handler.go index 679a3b1a78..129f42647a 100644 --- a/types/handler.go +++ b/types/handler.go @@ -3,8 +3,5 @@ package types // core function variable which application runs for transactions type Handler func(ctx Context, msg Msg) Result -// core function variable which application runs to handle fees -type FeeHandler func(ctx Context, tx Tx, fee Coins) - // If newCtx.IsZero(), ctx is used instead. type AnteHandler func(ctx Context, tx Tx) (newCtx Context, result Result, abort bool) diff --git a/types/signature.go b/types/signature.go deleted file mode 100644 index 5bca2f6069..0000000000 --- a/types/signature.go +++ /dev/null @@ -1,10 +0,0 @@ -package types - -import crypto "github.com/tendermint/go-crypto" - -// Standard Signature -type StdSignature struct { - crypto.PubKey `json:"pub_key"` // optional - crypto.Signature `json:"signature"` - Sequence int64 `json:"sequence"` -} diff --git a/types/tx_msg.go b/types/tx_msg.go index e17d152a5f..186cf9b242 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -31,123 +31,6 @@ type Tx interface { // Gets the Msg. GetMsg() Msg - - // Signatures returns the signature of signers who signed the Msg. - // CONTRACT: Length returned is same as length of - // pubkeys returned from MsgKeySigners, and the order - // matches. - // CONTRACT: If the signature is missing (ie the Msg is - // invalid), then the corresponding signature is - // .Empty(). - GetSignatures() []StdSignature -} - -var _ Tx = (*StdTx)(nil) - -// StdTx is a standard way to wrap a Msg with Fee and Signatures. -// NOTE: the first signature is the FeePayer (Signatures must not be nil). -type StdTx struct { - Msg `json:"msg"` - Fee StdFee `json:"fee"` - Signatures []StdSignature `json:"signatures"` -} - -func NewStdTx(msg Msg, fee StdFee, sigs []StdSignature) StdTx { - return StdTx{ - Msg: msg, - Fee: fee, - Signatures: sigs, - } -} - -//nolint -func (tx StdTx) GetMsg() Msg { return tx.Msg } -func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures } - -// FeePayer returns the address responsible for paying the fees -// for the transactions. It's the first address returned by msg.GetSigners(). -// If GetSigners() is empty, this panics. -func FeePayer(tx Tx) Address { - return tx.GetMsg().GetSigners()[0] -} - -//__________________________________________________________ - -// StdFee includes the amount of coins paid in fees and the maximum -// gas to be used by the transaction. The ratio yields an effective "gasprice", -// which must be above some miminum to be accepted into the mempool. -type StdFee struct { - Amount Coins `json:"amount"` - Gas int64 `json:"gas"` -} - -func NewStdFee(gas int64, amount ...Coin) StdFee { - return StdFee{ - Amount: amount, - Gas: gas, - } -} - -// fee bytes for signing later -func (fee StdFee) Bytes() []byte { - // normalize. XXX - // this is a sign of something ugly - // (in the lcd_test, client side its null, - // server side its []) - if len(fee.Amount) == 0 { - fee.Amount = Coins{} - } - bz, err := json.Marshal(fee) // TODO - if err != nil { - panic(err) - } - return bz -} - -//__________________________________________________________ - -// StdSignDoc is replay-prevention structure. -// It includes the result of msg.GetSignBytes(), -// as well as the ChainID (prevent cross chain replay) -// and the Sequence numbers for each signature (prevent -// inchain replay and enforce tx ordering per account). -type StdSignDoc struct { - ChainID string `json:"chain_id"` - Sequences []int64 `json:"sequences"` - FeeBytes []byte `json:"fee_bytes"` - MsgBytes []byte `json:"msg_bytes"` - AltBytes []byte `json:"alt_bytes"` -} - -// StdSignBytes returns the bytes to sign for a transaction. -// TODO: change the API to just take a chainID and StdTx ? -func StdSignBytes(chainID string, sequences []int64, fee StdFee, msg Msg) []byte { - bz, err := json.Marshal(StdSignDoc{ - ChainID: chainID, - Sequences: sequences, - FeeBytes: fee.Bytes(), - MsgBytes: msg.GetSignBytes(), - }) - if err != nil { - panic(err) - } - return bz -} - -// StdSignMsg is a convenience structure for passing along -// a Msg with the other requirements for a StdSignDoc before -// it is signed. For use in the CLI. -type StdSignMsg struct { - ChainID string - Sequences []int64 - Fee StdFee - Msg Msg - // XXX: Alt -} - -// get message bytes -func (msg StdSignMsg) Bytes() []byte { - return StdSignBytes(msg.ChainID, msg.Sequences, msg.Fee, msg.Msg) } //__________________________________________________________ diff --git a/x/auth/account.go b/x/auth/account.go new file mode 100644 index 0000000000..28366467aa --- /dev/null +++ b/x/auth/account.go @@ -0,0 +1,25 @@ +package auth + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + crypto "github.com/tendermint/go-crypto" +) + +// Account is a standard account using a sequence number for replay protection +// and a pubkey for authentication. +type Account interface { + GetAddress() sdk.Address + SetAddress(sdk.Address) error // errors if already set. + + GetPubKey() crypto.PubKey // can return nil. + SetPubKey(crypto.PubKey) error + + GetSequence() int64 + SetSequence(int64) error + + GetCoins() sdk.Coins + SetCoins(sdk.Coins) error +} + +// AccountDecoder unmarshals account bytes +type AccountDecoder func(accountBytes []byte) (Account, error) diff --git a/x/auth/ante.go b/x/auth/ante.go index 248083206d..2139524077 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -15,13 +15,20 @@ const ( // NewAnteHandler returns an AnteHandler that checks // and increments sequence numbers, checks signatures, // and deducts fees from the first signer. -func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHandler { +func NewAnteHandler(am AccountMapper) sdk.AnteHandler { + return func( ctx sdk.Context, tx sdk.Tx, ) (_ sdk.Context, _ sdk.Result, abort bool) { + // This AnteHandler requires Txs to be StdTxs + stdTx, ok := tx.(StdTx) + if !ok { + return ctx, sdk.ErrInternal("tx must be sdk.StdTx").Result(), true + } + // Assert that there are signatures. - var sigs = tx.GetSignatures() + var sigs = stdTx.GetSignatures() if len(sigs) == 0 { return ctx, sdk.ErrUnauthorized("no signers").Result(), @@ -30,12 +37,6 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan msg := tx.GetMsg() - // TODO: will this always be a stdtx? should that be used in the function signature? - stdTx, ok := tx.(sdk.StdTx) - if !ok { - return ctx, sdk.ErrInternal("tx must be sdk.StdTx").Result(), true - } - // Assert that number of signatures is correct. var signerAddrs = msg.GetSigners() if len(sigs) != len(signerAddrs) { @@ -56,10 +57,10 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan if chainID == "" { chainID = viper.GetString("chain-id") } - signBytes := sdk.StdSignBytes(ctx.ChainID(), sequences, fee, msg) + signBytes := StdSignBytes(ctx.ChainID(), sequences, fee, msg) // Check sig and nonce and collect signer accounts. - var signerAccs = make([]sdk.Account, len(signerAddrs)) + var signerAccs = make([]Account, len(signerAddrs)) for i := 0; i < len(sigs); i++ { signerAddr, sig := signerAddrs[i], sigs[i] @@ -77,7 +78,6 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan // TODO: min fee if !fee.Amount.IsZero() { signerAcc, res = deductFees(signerAcc, fee) - feeHandler(ctx, tx, fee.Amount) if !res.IsOK() { return ctx, res, true } @@ -104,9 +104,9 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan // verify the signature and increment the sequence. // if the account doesn't have a pubkey, set it. func processSig( - ctx sdk.Context, am sdk.AccountMapper, - addr sdk.Address, sig sdk.StdSignature, signBytes []byte) ( - acc sdk.Account, res sdk.Result) { + ctx sdk.Context, am AccountMapper, + addr sdk.Address, sig StdSignature, signBytes []byte) ( + acc Account, res sdk.Result) { // Get the account. acc = am.GetAccount(ctx, addr) @@ -152,7 +152,7 @@ func processSig( // Deduct the fee from the account. // We could use the CoinKeeper (in addition to the AccountMapper, // because the CoinKeeper doesn't give us accounts), but it seems easier to do this. -func deductFees(acc sdk.Account, fee sdk.StdFee) (sdk.Account, sdk.Result) { +func deductFees(acc Account, fee StdFee) (Account, sdk.Result) { coins := acc.GetCoins() feeAmount := fee.Amount diff --git a/x/auth/client/cli/account.go b/x/auth/client/cli/account.go index b45cb12ddf..08bd520fb1 100644 --- a/x/auth/client/cli/account.go +++ b/x/auth/client/cli/account.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) // GetAccountCmd for the auth.BaseAccount type @@ -17,8 +18,8 @@ func GetAccountCmdDefault(storeName string, cdc *wire.Codec) *cobra.Command { } // Get account decoder for auth.DefaultAccount -func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder { - return func(accBytes []byte) (acct sdk.Account, err error) { +func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder { + return func(accBytes []byte) (acct auth.Account, err error) { // acct := new(auth.BaseAccount) err = cdc.UnmarshalBinaryBare(accBytes, &acct) if err != nil { @@ -30,7 +31,7 @@ func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder { // GetAccountCmd returns a query account that will display the // state of the account at a given address -func GetAccountCmd(storeName string, cdc *wire.Codec, decoder sdk.AccountDecoder) *cobra.Command { +func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder) *cobra.Command { return &cobra.Command{ Use: "account [address]", Short: "Query account balance", diff --git a/x/auth/context.go b/x/auth/context.go index b233f1e861..40fb177858 100644 --- a/x/auth/context.go +++ b/x/auth/context.go @@ -34,15 +34,15 @@ const ( ) // add the signers to the context -func WithSigners(ctx types.Context, accounts []types.Account) types.Context { +func WithSigners(ctx types.Context, accounts []Account) types.Context { return ctx.WithValue(contextKeySigners, accounts) } // get the signers from the context -func GetSigners(ctx types.Context) []types.Account { +func GetSigners(ctx types.Context) []Account { v := ctx.Value(contextKeySigners) if v == nil { - return []types.Account{} + return []Account{} } - return v.([]types.Account) + return v.([]Account) } diff --git a/x/auth/mapper.go b/x/auth/mapper.go index 3666f13b69..cdab2480e3 100644 --- a/x/auth/mapper.go +++ b/x/auth/mapper.go @@ -9,9 +9,6 @@ import ( crypto "github.com/tendermint/go-crypto" ) -var _ sdk.AccountMapper = (*AccountMapper)(nil) - -// Implements sdk.AccountMapper. // This AccountMapper encodes/decodes accounts using the // go-amino (binary) encoding/decoding library. type AccountMapper struct { @@ -19,8 +16,8 @@ type AccountMapper struct { // The (unexposed) key used to access the store from the Context. key sdk.StoreKey - // The prototypical sdk.Account concrete type. - proto sdk.Account + // The prototypical Account concrete type. + proto Account // The wire codec for binary encoding/decoding of accounts. cdc *wire.Codec @@ -29,7 +26,7 @@ type AccountMapper struct { // NewAccountMapper returns a new sdk.AccountMapper that // uses go-amino to (binary) encode and decode concrete sdk.Accounts. // nolint -func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto sdk.Account) AccountMapper { +func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto Account) AccountMapper { return AccountMapper{ key: key, proto: proto, @@ -38,14 +35,14 @@ func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto sdk.Account) Acco } // Implaements sdk.AccountMapper. -func (am AccountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.Address) sdk.Account { +func (am AccountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.Address) Account { acc := am.clonePrototype() acc.SetAddress(addr) return acc } // Implements sdk.AccountMapper. -func (am AccountMapper) GetAccount(ctx sdk.Context, addr sdk.Address) sdk.Account { +func (am AccountMapper) GetAccount(ctx sdk.Context, addr sdk.Address) Account { store := ctx.KVStore(am.key) bz := store.Get(addr) if bz == nil { @@ -56,7 +53,7 @@ func (am AccountMapper) GetAccount(ctx sdk.Context, addr sdk.Address) sdk.Accoun } // Implements sdk.AccountMapper. -func (am AccountMapper) SetAccount(ctx sdk.Context, acc sdk.Account) { +func (am AccountMapper) SetAccount(ctx sdk.Context, acc Account) { addr := acc.GetAddress() store := ctx.KVStore(am.key) bz := am.encodeAccount(acc) @@ -64,7 +61,7 @@ func (am AccountMapper) SetAccount(ctx sdk.Context, acc sdk.Account) { } // Implements sdk.AccountMapper. -func (am AccountMapper) IterateAccounts(ctx sdk.Context, process func(sdk.Account) (stop bool)) { +func (am AccountMapper) IterateAccounts(ctx sdk.Context, process func(Account) (stop bool)) { store := ctx.KVStore(am.key) iter := store.Iterator(nil, nil) for { @@ -89,7 +86,8 @@ func (am AccountMapper) GetPubKey(ctx sdk.Context, addr sdk.Address) (crypto.Pub return acc.GetPubKey(), nil } -func (am AccountMapper) setPubKey(ctx sdk.Context, addr sdk.Address, newPubKey crypto.PubKey) sdk.Error { +// Sets the PubKey of the account at address +func (am AccountMapper) SetPubKey(ctx sdk.Context, addr sdk.Address, newPubKey crypto.PubKey) sdk.Error { acc := am.GetAccount(ctx, addr) if acc == nil { return sdk.ErrUnknownAddress(addr.String()) @@ -122,7 +120,7 @@ func (am AccountMapper) setSequence(ctx sdk.Context, addr sdk.Address, newSequen // misc. // Creates a new struct (or pointer to struct) from am.proto. -func (am AccountMapper) clonePrototype() sdk.Account { +func (am AccountMapper) clonePrototype() Account { protoRt := reflect.TypeOf(am.proto) if protoRt.Kind() == reflect.Ptr { protoCrt := protoRt.Elem() @@ -130,7 +128,7 @@ func (am AccountMapper) clonePrototype() sdk.Account { panic("accountMapper requires a struct proto sdk.Account, or a pointer to one") } protoRv := reflect.New(protoCrt) - clone, ok := protoRv.Interface().(sdk.Account) + clone, ok := protoRv.Interface().(Account) if !ok { panic(fmt.Sprintf("accountMapper requires a proto sdk.Account, but %v doesn't implement sdk.Account", protoRt)) } @@ -138,14 +136,14 @@ func (am AccountMapper) clonePrototype() sdk.Account { } protoRv := reflect.New(protoRt).Elem() - clone, ok := protoRv.Interface().(sdk.Account) + clone, ok := protoRv.Interface().(Account) if !ok { panic(fmt.Sprintf("accountMapper requires a proto sdk.Account, but %v doesn't implement sdk.Account", protoRt)) } return clone } -func (am AccountMapper) encodeAccount(acc sdk.Account) []byte { +func (am AccountMapper) encodeAccount(acc Account) []byte { bz, err := am.cdc.MarshalBinaryBare(acc) if err != nil { panic(err) @@ -153,7 +151,7 @@ func (am AccountMapper) encodeAccount(acc sdk.Account) []byte { return bz } -func (am AccountMapper) decodeAccount(bz []byte) (acc sdk.Account) { +func (am AccountMapper) decodeAccount(bz []byte) (acc Account) { err := am.cdc.UnmarshalBinaryBare(bz, &acc) if err != nil { panic(err) diff --git a/x/auth/stdtx.go b/x/auth/stdtx.go new file mode 100644 index 0000000000..bc01b01490 --- /dev/null +++ b/x/auth/stdtx.go @@ -0,0 +1,131 @@ +package auth + +import ( + "encoding/json" + + sdk "github.com/cosmos/cosmos-sdk/types" + crypto "github.com/tendermint/go-crypto" +) + +var _ sdk.Tx = (*StdTx)(nil) + +// StdTx is a standard way to wrap a Msg with Fee and Signatures. +// NOTE: the first signature is the FeePayer (Signatures must not be nil). +type StdTx struct { + Msg sdk.Msg `json:"msg"` + Fee StdFee `json:"fee"` + Signatures []StdSignature `json:"signatures"` +} + +func NewStdTx(msg sdk.Msg, fee StdFee, sigs []StdSignature) StdTx { + return StdTx{ + Msg: msg, + Fee: fee, + Signatures: sigs, + } +} + +//nolint +func (tx StdTx) GetMsg() sdk.Msg { return tx.Msg } + +// Signatures returns the signature of signers who signed the Msg. +// CONTRACT: Length returned is same as length of +// pubkeys returned from MsgKeySigners, and the order +// matches. +// CONTRACT: If the signature is missing (ie the Msg is +// invalid), then the corresponding signature is +// .Empty(). +func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures } + +// FeePayer returns the address responsible for paying the fees +// for the transactions. It's the first address returned by msg.GetSigners(). +// If GetSigners() is empty, this panics. +func FeePayer(tx sdk.Tx) sdk.Address { + return tx.GetMsg().GetSigners()[0] +} + +//__________________________________________________________ + +// StdFee includes the amount of coins paid in fees and the maximum +// gas to be used by the transaction. The ratio yields an effective "gasprice", +// which must be above some miminum to be accepted into the mempool. +type StdFee struct { + Amount sdk.Coins `json:"amount"` + Gas int64 `json:"gas"` +} + +func NewStdFee(gas int64, amount ...sdk.Coin) StdFee { + return StdFee{ + Amount: amount, + Gas: gas, + } +} + +// fee bytes for signing later +func (fee StdFee) Bytes() []byte { + // normalize. XXX + // this is a sign of something ugly + // (in the lcd_test, client side its null, + // server side its []) + if len(fee.Amount) == 0 { + fee.Amount = sdk.Coins{} + } + bz, err := json.Marshal(fee) // TODO + if err != nil { + panic(err) + } + return bz +} + +//__________________________________________________________ + +// StdSignDoc is replay-prevention structure. +// It includes the result of msg.GetSignBytes(), +// as well as the ChainID (prevent cross chain replay) +// and the Sequence numbers for each signature (prevent +// inchain replay and enforce tx ordering per account). +type StdSignDoc struct { + ChainID string `json:"chain_id"` + Sequences []int64 `json:"sequences"` + FeeBytes []byte `json:"fee_bytes"` + MsgBytes []byte `json:"msg_bytes"` + AltBytes []byte `json:"alt_bytes"` +} + +// StdSignBytes returns the bytes to sign for a transaction. +// TODO: change the API to just take a chainID and StdTx ? +func StdSignBytes(chainID string, sequences []int64, fee StdFee, msg sdk.Msg) []byte { + bz, err := json.Marshal(StdSignDoc{ + ChainID: chainID, + Sequences: sequences, + FeeBytes: fee.Bytes(), + MsgBytes: msg.GetSignBytes(), + }) + if err != nil { + panic(err) + } + return bz +} + +// StdSignMsg is a convenience structure for passing along +// a Msg with the other requirements for a StdSignDoc before +// it is signed. For use in the CLI. +type StdSignMsg struct { + ChainID string + Sequences []int64 + Fee StdFee + Msg sdk.Msg + // XXX: Alt +} + +// get message bytes +func (msg StdSignMsg) Bytes() []byte { + return StdSignBytes(msg.ChainID, msg.Sequences, msg.Fee, msg.Msg) +} + +// Standard Signature +type StdSignature struct { + crypto.PubKey `json:"pub_key"` // optional + crypto.Signature `json:"signature"` + Sequence int64 `json:"sequence"` +} diff --git a/x/auth/wire.go b/x/auth/wire.go deleted file mode 100644 index 9db1b85cca..0000000000 --- a/x/auth/wire.go +++ /dev/null @@ -1,12 +0,0 @@ -package auth - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/wire" -) - -// Register concrete types on wire codec for default AppAccount -func RegisterWire(cdc *wire.Codec) { - cdc.RegisterInterface((*sdk.Account)(nil), nil) - cdc.RegisterConcrete(&BaseAccount{}, "auth/Account", nil) -} diff --git a/x/bank/keeper.go b/x/bank/keeper.go index 6ef73c68b6..b14da4d81f 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) const ( @@ -16,11 +17,11 @@ const ( // Keeper manages transfers between accounts type Keeper struct { - am sdk.AccountMapper + am auth.AccountMapper } // NewKeeper returns a new Keeper -func NewKeeper(am sdk.AccountMapper) Keeper { +func NewKeeper(am auth.AccountMapper) Keeper { return Keeper{am: am} } @@ -63,11 +64,11 @@ func (keeper Keeper) InputOutputCoins(ctx sdk.Context, inputs []Input, outputs [ // SendKeeper only allows transfers between accounts, without the possibility of creating coins type SendKeeper struct { - am sdk.AccountMapper + am auth.AccountMapper } // NewSendKeeper returns a new Keeper -func NewSendKeeper(am sdk.AccountMapper) SendKeeper { +func NewSendKeeper(am auth.AccountMapper) SendKeeper { return SendKeeper{am: am} } @@ -95,11 +96,11 @@ func (keeper SendKeeper) InputOutputCoins(ctx sdk.Context, inputs []Input, outpu // ViewKeeper only allows reading of balances type ViewKeeper struct { - am sdk.AccountMapper + am auth.AccountMapper } // NewViewKeeper returns a new Keeper -func NewViewKeeper(am sdk.AccountMapper) ViewKeeper { +func NewViewKeeper(am auth.AccountMapper) ViewKeeper { return ViewKeeper{am: am} } @@ -115,7 +116,7 @@ func (keeper ViewKeeper) HasCoins(ctx sdk.Context, addr sdk.Address, amt sdk.Coi //______________________________________________________________________________________________ -func getCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address) sdk.Coins { +func getCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address) sdk.Coins { ctx.GasMeter().ConsumeGas(costGetCoins, "getCoins") acc := am.GetAccount(ctx, addr) if acc == nil { @@ -124,7 +125,7 @@ func getCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address) sdk.Coins return acc.GetCoins() } -func setCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) sdk.Error { +func setCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk.Coins) sdk.Error { ctx.GasMeter().ConsumeGas(costSetCoins, "setCoins") acc := am.GetAccount(ctx, addr) if acc == nil { @@ -136,13 +137,13 @@ func setCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.C } // HasCoins returns whether or not an account has at least amt coins. -func hasCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) bool { +func hasCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk.Coins) bool { ctx.GasMeter().ConsumeGas(costHasCoins, "hasCoins") return getCoins(ctx, am, addr).IsGTE(amt) } // SubtractCoins subtracts amt from the coins at the addr. -func subtractCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { +func subtractCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { ctx.GasMeter().ConsumeGas(costSubtractCoins, "subtractCoins") oldCoins := getCoins(ctx, am, addr) newCoins := oldCoins.Minus(amt) @@ -155,7 +156,7 @@ func subtractCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt } // AddCoins adds amt to the coins at the addr. -func addCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { +func addCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { ctx.GasMeter().ConsumeGas(costAddCoins, "addCoins") oldCoins := getCoins(ctx, am, addr) newCoins := oldCoins.Plus(amt) @@ -169,7 +170,7 @@ func addCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.C // SendCoins moves coins from one account to another // NOTE: Make sure to revert state changes from tx on error -func sendCoins(ctx sdk.Context, am sdk.AccountMapper, fromAddr sdk.Address, toAddr sdk.Address, amt sdk.Coins) (sdk.Tags, sdk.Error) { +func sendCoins(ctx sdk.Context, am auth.AccountMapper, fromAddr sdk.Address, toAddr sdk.Address, amt sdk.Coins) (sdk.Tags, sdk.Error) { _, subTags, err := subtractCoins(ctx, am, fromAddr, amt) if err != nil { return nil, err @@ -185,7 +186,7 @@ func sendCoins(ctx sdk.Context, am sdk.AccountMapper, fromAddr sdk.Address, toAd // InputOutputCoins handles a list of inputs and outputs // NOTE: Make sure to revert state changes from tx on error -func inputOutputCoins(ctx sdk.Context, am sdk.AccountMapper, inputs []Input, outputs []Output) (sdk.Tags, sdk.Error) { +func inputOutputCoins(ctx sdk.Context, am auth.AccountMapper, inputs []Input, outputs []Output) (sdk.Tags, sdk.Error) { allTags := sdk.EmptyTags() for _, in := range inputs { diff --git a/x/auth/baseaccount.go b/x/baseaccount/baseaccount.go similarity index 90% rename from x/auth/baseaccount.go rename to x/baseaccount/baseaccount.go index ff907fc387..9701ac41dc 100644 --- a/x/auth/baseaccount.go +++ b/x/baseaccount/baseaccount.go @@ -1,18 +1,19 @@ -package auth +package baseaccount import ( "errors" - "github.com/tendermint/go-crypto" + crypto "github.com/tendermint/go-crypto" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) //----------------------------------------------------------- // BaseAccount -var _ sdk.Account = (*BaseAccount)(nil) +var _ auth.Account = (*BaseAccount)(nil) // BaseAccount - base account structure. // Extend this by embedding this in your AppAccount. @@ -82,7 +83,7 @@ func (acc *BaseAccount) SetSequence(seq int64) error { // Most users shouldn't use this, but this comes handy for tests. func RegisterBaseAccount(cdc *wire.Codec) { - cdc.RegisterInterface((*sdk.Account)(nil), nil) + cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterConcrete(&BaseAccount{}, "cosmos-sdk/BaseAccount", nil) wire.RegisterCrypto(cdc) } diff --git a/x/auth/baseaccount_test.go b/x/baseaccount/baseaccount_test.go similarity index 99% rename from x/auth/baseaccount_test.go rename to x/baseaccount/baseaccount_test.go index d3363e4fb0..ed1a322c2f 100644 --- a/x/auth/baseaccount_test.go +++ b/x/baseaccount/baseaccount_test.go @@ -1,4 +1,4 @@ -package auth +package baseaccount import ( "testing" diff --git a/x/auth/handler.go b/x/baseaccount/handler.go similarity index 58% rename from x/auth/handler.go rename to x/baseaccount/handler.go index 8a0e1061ae..46307c8818 100644 --- a/x/auth/handler.go +++ b/x/baseaccount/handler.go @@ -1,19 +1,20 @@ -package auth +package baseaccount import ( "reflect" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) -// NewHandler returns a handler for "auth" type messages. -func NewHandler(am AccountMapper) sdk.Handler { +// NewHandler returns a handler for "baseaccount" type messages. +func NewHandler(am auth.AccountMapper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case MsgChangeKey: return handleMsgChangeKey(ctx, am, msg) default: - errMsg := "Unrecognized auth Msg type: " + reflect.TypeOf(msg).Name() + errMsg := "Unrecognized baseaccount Msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() } } @@ -21,9 +22,9 @@ func NewHandler(am AccountMapper) sdk.Handler { // Handle MsgChangeKey // Should be very expensive, because once this happens, an account is un-prunable -func handleMsgChangeKey(ctx sdk.Context, am AccountMapper, msg MsgChangeKey) sdk.Result { +func handleMsgChangeKey(ctx sdk.Context, am auth.AccountMapper, msg MsgChangeKey) sdk.Result { - err := am.setPubKey(ctx, msg.Address, msg.NewPubKey) + err := am.SetPubKey(ctx, msg.Address, msg.NewPubKey) if err != nil { return err.Result() } diff --git a/x/auth/msgs.go b/x/baseaccount/msgs.go similarity index 87% rename from x/auth/msgs.go rename to x/baseaccount/msgs.go index 545b296e5b..f0319ac7fe 100644 --- a/x/auth/msgs.go +++ b/x/baseaccount/msgs.go @@ -1,11 +1,10 @@ -package auth +package baseaccount import ( "encoding/json" - "github.com/tendermint/go-crypto" - sdk "github.com/cosmos/cosmos-sdk/types" + crypto "github.com/tendermint/go-crypto" ) // MsgChangeKey - high level transaction of the auth module @@ -22,7 +21,7 @@ func NewMsgChangeKey(addr sdk.Address, pubkey crypto.PubKey) MsgChangeKey { } // Implements Msg. -func (msg MsgChangeKey) Type() string { return "auth" } +func (msg MsgChangeKey) Type() string { return "baseaccount" } // Implements Msg. func (msg MsgChangeKey) ValidateBasic() sdk.Error { diff --git a/x/auth/msgs_test.go b/x/baseaccount/msgs_test.go similarity index 97% rename from x/auth/msgs_test.go rename to x/baseaccount/msgs_test.go index 30c98b073b..46797fa0d8 100644 --- a/x/auth/msgs_test.go +++ b/x/baseaccount/msgs_test.go @@ -1,4 +1,4 @@ -package auth +package baseaccount import ( "testing" diff --git a/x/baseaccount/wire.go b/x/baseaccount/wire.go new file mode 100644 index 0000000000..4c77d1c72c --- /dev/null +++ b/x/baseaccount/wire.go @@ -0,0 +1,14 @@ +package baseaccount + +import ( + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" +) + +// Register concrete types on wire codec +func RegisterWire(cdc *wire.Codec) { + cdc.RegisterInterface((*auth.Account)(nil), nil) + cdc.RegisterConcrete(&BaseAccount{}, "baseaccount/BaseAccount", nil) + wire.RegisterCrypto(cdc) + cdc.RegisterConcrete(MsgChangeKey{}, "baseaccount/changekey", nil) +} diff --git a/x/stake/test_common.go b/x/stake/test_common.go index 27acebe086..5a87081af1 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -17,6 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/baseaccount" ) // dummy addresses used for testing @@ -129,8 +130,8 @@ func makeTestCodec() *wire.Codec { cdc.RegisterConcrete(MsgUnbond{}, "test/stake/Unbond", nil) // Register AppAccount - cdc.RegisterInterface((*sdk.Account)(nil), nil) - cdc.RegisterConcrete(&auth.BaseAccount{}, "test/stake/Account", nil) + cdc.RegisterInterface((*auth.Account)(nil), nil) + cdc.RegisterConcrete(&baseaccount.BaseAccount{}, "test/stake/Account", nil) wire.RegisterCrypto(cdc) return cdc @@ -148,7 +149,7 @@ func paramsNoInflation() Params { } // hogpodge of all sorts of input required for testing -func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context, sdk.AccountMapper, Keeper) { +func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context, auth.AccountMapper, Keeper) { db := dbm.NewMemDB() keyStake := sdk.NewKVStoreKey("stake") keyMain := keyStake //sdk.NewKVStoreKey("main") //TODO fix multistore @@ -161,9 +162,9 @@ func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil, log.NewNopLogger()) cdc := makeTestCodec() accountMapper := auth.NewAccountMapper( - cdc, // amino codec - keyMain, // target store - &auth.BaseAccount{}, // prototype + cdc, // amino codec + keyMain, // target store + &baseaccount.BaseAccount{}, // prototype ) ck := bank.NewKeeper(accountMapper) keeper := NewKeeper(cdc, keyStake, ck, DefaultCodespace) From 34a10072b4c9ded9d70250c55f7c476e9de71893 Mon Sep 17 00:00:00 2001 From: sunnya97 Date: Wed, 23 May 2018 19:47:33 -0700 Subject: [PATCH 12/21] in progress --- x/auth/client/rest/query.go | 7 ++++--- x/ibc/client/cli/relay.go | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index 52244fec9c..a60ce5cdb2 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -10,19 +10,20 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" - auth "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + "github.com/cosmos/cosmos-sdk/x/auth" + authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" ) // register REST routes func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, storeName string) { r.HandleFunc( "/accounts/{address}", - QueryAccountRequestHandlerFn(storeName, cdc, auth.GetAccountDecoder(cdc), ctx), + QueryAccountRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), ctx), ).Methods("GET") } // query accountREST Handler -func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder sdk.AccountDecoder, ctx context.CoreContext) http.HandlerFunc { +func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) addr := vars["address"] diff --git a/x/ibc/client/cli/relay.go b/x/ibc/client/cli/relay.go index 86e8b1dbf8..7fd9a8fcc1 100644 --- a/x/ibc/client/cli/relay.go +++ b/x/ibc/client/cli/relay.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/ibc" ) @@ -27,7 +28,7 @@ const ( type relayCommander struct { cdc *wire.Codec address sdk.Address - decoder sdk.AccountDecoder + decoder auth.AccountDecoder mainStore string ibcStore string From cb527126600cddd895f5671bed8dbcdca270415d Mon Sep 17 00:00:00 2001 From: sunnya97 Date: Wed, 23 May 2018 19:26:54 -0700 Subject: [PATCH 13/21] in progress --- baseapp/baseapp.go | 3 +- client/context/helpers.go | 9 +- client/context/types.go | 6 +- client/tx/query.go | 3 +- cmd/gaia/app/app.go | 18 ++- cmd/gaia/app/genesis.go | 11 +- types/account.go | 29 ----- types/handler.go | 3 - types/signature.go | 10 -- types/tx_msg.go | 117 ----------------- x/auth/account.go | 25 ++++ x/auth/ante.go | 30 ++--- x/auth/client/cli/account.go | 7 +- x/auth/context.go | 8 +- x/auth/mapper.go | 30 +++-- x/auth/stdtx.go | 131 ++++++++++++++++++++ x/auth/wire.go | 12 -- x/bank/keeper.go | 27 ++-- x/{auth => baseaccount}/baseaccount.go | 9 +- x/{auth => baseaccount}/baseaccount_test.go | 2 +- x/{auth => baseaccount}/handler.go | 13 +- x/{auth => baseaccount}/msgs.go | 7 +- x/{auth => baseaccount}/msgs_test.go | 2 +- x/baseaccount/wire.go | 14 +++ x/stake/test_common.go | 16 ++- 25 files changed, 280 insertions(+), 262 deletions(-) delete mode 100644 types/signature.go create mode 100644 x/auth/account.go create mode 100644 x/auth/stdtx.go delete mode 100644 x/auth/wire.go rename x/{auth => baseaccount}/baseaccount.go (90%) rename x/{auth => baseaccount}/baseaccount_test.go (99%) rename x/{auth => baseaccount}/handler.go (58%) rename x/{auth => baseaccount}/msgs.go (87%) rename x/{auth => baseaccount}/msgs_test.go (97%) create mode 100644 x/baseaccount/wire.go diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index ef3bbc3c79..4ce8a05d9b 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -15,6 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) // Key to store the header in the DB itself. @@ -125,7 +126,7 @@ func (app *BaseApp) SetTxDecoder(txDecoder sdk.TxDecoder) { // default custom logic for transaction decoding func defaultTxDecoder(cdc *wire.Codec) sdk.TxDecoder { return func(txBytes []byte) (sdk.Tx, sdk.Error) { - var tx = sdk.StdTx{} + var tx = auth.StdTx{} if len(txBytes) == 0 { return nil, sdk.ErrTxDecode("txBytes are empty") diff --git a/client/context/helpers.go b/client/context/helpers.go index 562bde9b4c..f4686befde 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" cmn "github.com/tendermint/tmlibs/common" @@ -109,11 +110,11 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w return nil, errors.Errorf("Chain ID required but not specified") } sequence := ctx.Sequence - signMsg := sdk.StdSignMsg{ + signMsg := auth.StdSignMsg{ ChainID: chainID, Sequences: []int64{sequence}, Msg: msg, - Fee: sdk.NewStdFee(10000, sdk.Coin{}), // TODO run simulate to estimate gas? + Fee: auth.NewStdFee(10000, sdk.Coin{}), // TODO run simulate to estimate gas? } keybase, err := keys.GetKeyBase() @@ -128,14 +129,14 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w if err != nil { return nil, err } - sigs := []sdk.StdSignature{{ + sigs := []auth.StdSignature{{ PubKey: pubkey, Signature: sig, Sequence: sequence, }} // marshal bytes - tx := sdk.NewStdTx(signMsg.Msg, signMsg.Fee, sigs) + tx := auth.NewStdTx(signMsg.Msg, signMsg.Fee, sigs) return cdc.MarshalBinary(tx) } diff --git a/client/context/types.go b/client/context/types.go index e580027d67..da15b32936 100644 --- a/client/context/types.go +++ b/client/context/types.go @@ -3,7 +3,7 @@ package context import ( rpcclient "github.com/tendermint/tendermint/rpc/client" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) // typical context created in sdk modules for transactions/queries @@ -15,7 +15,7 @@ type CoreContext struct { FromAddressName string Sequence int64 Client rpcclient.Client - Decoder sdk.AccountDecoder + Decoder auth.AccountDecoder AccountStore string } @@ -63,7 +63,7 @@ func (c CoreContext) WithClient(client rpcclient.Client) CoreContext { } // WithDecoder - return a copy of the context with an updated Decoder -func (c CoreContext) WithDecoder(decoder sdk.AccountDecoder) CoreContext { +func (c CoreContext) WithDecoder(decoder auth.AccountDecoder) CoreContext { c.Decoder = decoder return c } diff --git a/client/tx/query.go b/client/tx/query.go index 2078b78831..7673dd38db 100644 --- a/client/tx/query.go +++ b/client/tx/query.go @@ -17,6 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) // Get the default command for a tx query @@ -95,7 +96,7 @@ type txInfo struct { } func parseTx(cdc *wire.Codec, txBytes []byte) (sdk.Tx, error) { - var tx sdk.StdTx + var tx auth.StdTx err := cdc.UnmarshalBinary(txBytes, &tx) if err != nil { return nil, err diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 42869c9558..9436c8b0fc 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -14,7 +14,11 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" +<<<<<<< HEAD feed "github.com/cosmos/cosmos-sdk/x/fee_distribution" +======= + "github.com/cosmos/cosmos-sdk/x/baseaccount" +>>>>>>> in progress "github.com/cosmos/cosmos-sdk/x/ibc" "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -41,7 +45,7 @@ type GaiaApp struct { keyStake *sdk.KVStoreKey // Manage getting and setting accounts - accountMapper sdk.AccountMapper + accountMapper auth.AccountMapper coinKeeper bank.Keeper ibcMapper ibc.Mapper stakeKeeper stake.Keeper @@ -63,8 +67,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { // define the accountMapper app.accountMapper = auth.NewAccountMapper( app.cdc, - app.keyAccount, // target store - &auth.BaseAccount{}, // prototype + app.keyAccount, // target store + &baseaccount.BaseAccount{}, // prototype ) // add handlers @@ -82,7 +86,11 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { app.SetInitChainer(app.initChainer) app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper)) app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake) +<<<<<<< HEAD app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, feed.BurnFeeHandler)) +======= + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper)) +>>>>>>> in progress err := app.LoadLatestVersion(app.keyMain) if err != nil { cmn.Exit(err.Error()) @@ -97,7 +105,7 @@ func MakeCodec() *wire.Codec { ibc.RegisterWire(cdc) bank.RegisterWire(cdc) stake.RegisterWire(cdc) - auth.RegisterWire(cdc) + baseaccount.RegisterWire(cdc) sdk.RegisterWire(cdc) wire.RegisterCrypto(cdc) return cdc @@ -132,7 +140,7 @@ func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) { // iterate to get the accounts accounts := []GenesisAccount{} - appendAccount := func(acc sdk.Account) (stop bool) { + appendAccount := func(acc auth.Account) (stop bool) { account := NewGenesisAccountI(acc) accounts = append(accounts, account) return false diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 525fe8ab07..6914ec4927 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -13,6 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/baseaccount" "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -28,14 +29,14 @@ type GenesisAccount struct { Coins sdk.Coins `json:"coins"` } -func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount { +func NewGenesisAccount(acc *baseaccount.BaseAccount) GenesisAccount { return GenesisAccount{ Address: acc.Address, Coins: acc.Coins, } } -func NewGenesisAccountI(acc sdk.Account) GenesisAccount { +func NewGenesisAccountI(acc auth.Account) GenesisAccount { return GenesisAccount{ Address: acc.GetAddress(), Coins: acc.GetCoins(), @@ -43,8 +44,8 @@ func NewGenesisAccountI(acc sdk.Account) GenesisAccount { } // convert GenesisAccount to auth.BaseAccount -func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { - return &auth.BaseAccount{ +func (ga *GenesisAccount) ToAccount() (acc *baseaccount.BaseAccount) { + return &baseaccount.BaseAccount{ Address: ga.Address, Coins: ga.Coins.Sort(), } @@ -148,7 +149,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso } // create the genesis account, give'm few steaks and a buncha token with there name - accAuth := auth.NewBaseAccountWithAddress(genTx.Address) + accAuth := baseaccount.NewBaseAccountWithAddress(genTx.Address) accAuth.Coins = sdk.Coins{ {genTx.Name + "Token", 1000}, {"steak", freeFermionsAcc}, diff --git a/types/account.go b/types/account.go index 74cd87f38c..be8b90a1cd 100644 --- a/types/account.go +++ b/types/account.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "errors" - crypto "github.com/tendermint/go-crypto" cmn "github.com/tendermint/tmlibs/common" ) @@ -22,31 +21,3 @@ func GetAddress(address string) (addr Address, err error) { } return Address(bz), nil } - -// Account is a standard account using a sequence number for replay protection -// and a pubkey for authentication. -type Account interface { - GetAddress() Address - SetAddress(Address) error // errors if already set. - - GetPubKey() crypto.PubKey // can return nil. - SetPubKey(crypto.PubKey) error - - GetSequence() int64 - SetSequence(int64) error - - GetCoins() Coins - SetCoins(Coins) error -} - -// AccountMapper stores and retrieves accounts from stores -// retrieved from the context. -type AccountMapper interface { - NewAccountWithAddress(ctx Context, addr Address) Account - GetAccount(ctx Context, addr Address) Account - SetAccount(ctx Context, acc Account) - IterateAccounts(ctx Context, process func(Account) (stop bool)) -} - -// AccountDecoder unmarshals account bytes -type AccountDecoder func(accountBytes []byte) (Account, error) diff --git a/types/handler.go b/types/handler.go index 679a3b1a78..129f42647a 100644 --- a/types/handler.go +++ b/types/handler.go @@ -3,8 +3,5 @@ package types // core function variable which application runs for transactions type Handler func(ctx Context, msg Msg) Result -// core function variable which application runs to handle fees -type FeeHandler func(ctx Context, tx Tx, fee Coins) - // If newCtx.IsZero(), ctx is used instead. type AnteHandler func(ctx Context, tx Tx) (newCtx Context, result Result, abort bool) diff --git a/types/signature.go b/types/signature.go deleted file mode 100644 index 5bca2f6069..0000000000 --- a/types/signature.go +++ /dev/null @@ -1,10 +0,0 @@ -package types - -import crypto "github.com/tendermint/go-crypto" - -// Standard Signature -type StdSignature struct { - crypto.PubKey `json:"pub_key"` // optional - crypto.Signature `json:"signature"` - Sequence int64 `json:"sequence"` -} diff --git a/types/tx_msg.go b/types/tx_msg.go index e17d152a5f..186cf9b242 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -31,123 +31,6 @@ type Tx interface { // Gets the Msg. GetMsg() Msg - - // Signatures returns the signature of signers who signed the Msg. - // CONTRACT: Length returned is same as length of - // pubkeys returned from MsgKeySigners, and the order - // matches. - // CONTRACT: If the signature is missing (ie the Msg is - // invalid), then the corresponding signature is - // .Empty(). - GetSignatures() []StdSignature -} - -var _ Tx = (*StdTx)(nil) - -// StdTx is a standard way to wrap a Msg with Fee and Signatures. -// NOTE: the first signature is the FeePayer (Signatures must not be nil). -type StdTx struct { - Msg `json:"msg"` - Fee StdFee `json:"fee"` - Signatures []StdSignature `json:"signatures"` -} - -func NewStdTx(msg Msg, fee StdFee, sigs []StdSignature) StdTx { - return StdTx{ - Msg: msg, - Fee: fee, - Signatures: sigs, - } -} - -//nolint -func (tx StdTx) GetMsg() Msg { return tx.Msg } -func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures } - -// FeePayer returns the address responsible for paying the fees -// for the transactions. It's the first address returned by msg.GetSigners(). -// If GetSigners() is empty, this panics. -func FeePayer(tx Tx) Address { - return tx.GetMsg().GetSigners()[0] -} - -//__________________________________________________________ - -// StdFee includes the amount of coins paid in fees and the maximum -// gas to be used by the transaction. The ratio yields an effective "gasprice", -// which must be above some miminum to be accepted into the mempool. -type StdFee struct { - Amount Coins `json:"amount"` - Gas int64 `json:"gas"` -} - -func NewStdFee(gas int64, amount ...Coin) StdFee { - return StdFee{ - Amount: amount, - Gas: gas, - } -} - -// fee bytes for signing later -func (fee StdFee) Bytes() []byte { - // normalize. XXX - // this is a sign of something ugly - // (in the lcd_test, client side its null, - // server side its []) - if len(fee.Amount) == 0 { - fee.Amount = Coins{} - } - bz, err := json.Marshal(fee) // TODO - if err != nil { - panic(err) - } - return bz -} - -//__________________________________________________________ - -// StdSignDoc is replay-prevention structure. -// It includes the result of msg.GetSignBytes(), -// as well as the ChainID (prevent cross chain replay) -// and the Sequence numbers for each signature (prevent -// inchain replay and enforce tx ordering per account). -type StdSignDoc struct { - ChainID string `json:"chain_id"` - Sequences []int64 `json:"sequences"` - FeeBytes []byte `json:"fee_bytes"` - MsgBytes []byte `json:"msg_bytes"` - AltBytes []byte `json:"alt_bytes"` -} - -// StdSignBytes returns the bytes to sign for a transaction. -// TODO: change the API to just take a chainID and StdTx ? -func StdSignBytes(chainID string, sequences []int64, fee StdFee, msg Msg) []byte { - bz, err := json.Marshal(StdSignDoc{ - ChainID: chainID, - Sequences: sequences, - FeeBytes: fee.Bytes(), - MsgBytes: msg.GetSignBytes(), - }) - if err != nil { - panic(err) - } - return bz -} - -// StdSignMsg is a convenience structure for passing along -// a Msg with the other requirements for a StdSignDoc before -// it is signed. For use in the CLI. -type StdSignMsg struct { - ChainID string - Sequences []int64 - Fee StdFee - Msg Msg - // XXX: Alt -} - -// get message bytes -func (msg StdSignMsg) Bytes() []byte { - return StdSignBytes(msg.ChainID, msg.Sequences, msg.Fee, msg.Msg) } //__________________________________________________________ diff --git a/x/auth/account.go b/x/auth/account.go new file mode 100644 index 0000000000..28366467aa --- /dev/null +++ b/x/auth/account.go @@ -0,0 +1,25 @@ +package auth + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + crypto "github.com/tendermint/go-crypto" +) + +// Account is a standard account using a sequence number for replay protection +// and a pubkey for authentication. +type Account interface { + GetAddress() sdk.Address + SetAddress(sdk.Address) error // errors if already set. + + GetPubKey() crypto.PubKey // can return nil. + SetPubKey(crypto.PubKey) error + + GetSequence() int64 + SetSequence(int64) error + + GetCoins() sdk.Coins + SetCoins(sdk.Coins) error +} + +// AccountDecoder unmarshals account bytes +type AccountDecoder func(accountBytes []byte) (Account, error) diff --git a/x/auth/ante.go b/x/auth/ante.go index 21d17fb9be..d57c8558ef 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -15,13 +15,20 @@ const ( // NewAnteHandler returns an AnteHandler that checks // and increments sequence numbers, checks signatures, // and deducts fees from the first signer. -func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHandler { +func NewAnteHandler(am AccountMapper) sdk.AnteHandler { + return func( ctx sdk.Context, tx sdk.Tx, ) (_ sdk.Context, _ sdk.Result, abort bool) { + // This AnteHandler requires Txs to be StdTxs + stdTx, ok := tx.(StdTx) + if !ok { + return ctx, sdk.ErrInternal("tx must be sdk.StdTx").Result(), true + } + // Assert that there are signatures. - var sigs = tx.GetSignatures() + var sigs = stdTx.GetSignatures() if len(sigs) == 0 { return ctx, sdk.ErrUnauthorized("no signers").Result(), @@ -30,12 +37,6 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan msg := tx.GetMsg() - // TODO: will this always be a stdtx? should that be used in the function signature? - stdTx, ok := tx.(sdk.StdTx) - if !ok { - return ctx, sdk.ErrInternal("tx must be sdk.StdTx").Result(), true - } - // Assert that number of signatures is correct. var signerAddrs = msg.GetSigners() if len(sigs) != len(signerAddrs) { @@ -56,10 +57,10 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan if chainID == "" { chainID = viper.GetString("chain-id") } - signBytes := sdk.StdSignBytes(ctx.ChainID(), sequences, fee, msg) + signBytes := StdSignBytes(ctx.ChainID(), sequences, fee, msg) // Check sig and nonce and collect signer accounts. - var signerAccs = make([]sdk.Account, len(signerAddrs)) + var signerAccs = make([]Account, len(signerAddrs)) for i := 0; i < len(sigs); i++ { signerAddr, sig := signerAddrs[i], sigs[i] @@ -77,7 +78,6 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan // TODO: min fee if !fee.Amount.IsZero() { signerAcc, res = deductFees(signerAcc, fee) - feeHandler(ctx, tx, fee.Amount) if !res.IsOK() { return ctx, res, true } @@ -104,9 +104,9 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan // verify the signature and increment the sequence. // if the account doesn't have a pubkey, set it. func processSig( - ctx sdk.Context, am sdk.AccountMapper, - addr sdk.Address, sig sdk.StdSignature, signBytes []byte) ( - acc sdk.Account, res sdk.Result) { + ctx sdk.Context, am AccountMapper, + addr sdk.Address, sig StdSignature, signBytes []byte) ( + acc Account, res sdk.Result) { // Get the account. acc = am.GetAccount(ctx, addr) @@ -152,7 +152,7 @@ func processSig( // Deduct the fee from the account. // We could use the CoinKeeper (in addition to the AccountMapper, // because the CoinKeeper doesn't give us accounts), but it seems easier to do this. -func deductFees(acc sdk.Account, fee sdk.StdFee) (sdk.Account, sdk.Result) { +func deductFees(acc Account, fee StdFee) (Account, sdk.Result) { coins := acc.GetCoins() feeAmount := fee.Amount diff --git a/x/auth/client/cli/account.go b/x/auth/client/cli/account.go index b45cb12ddf..08bd520fb1 100644 --- a/x/auth/client/cli/account.go +++ b/x/auth/client/cli/account.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) // GetAccountCmd for the auth.BaseAccount type @@ -17,8 +18,8 @@ func GetAccountCmdDefault(storeName string, cdc *wire.Codec) *cobra.Command { } // Get account decoder for auth.DefaultAccount -func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder { - return func(accBytes []byte) (acct sdk.Account, err error) { +func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder { + return func(accBytes []byte) (acct auth.Account, err error) { // acct := new(auth.BaseAccount) err = cdc.UnmarshalBinaryBare(accBytes, &acct) if err != nil { @@ -30,7 +31,7 @@ func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder { // GetAccountCmd returns a query account that will display the // state of the account at a given address -func GetAccountCmd(storeName string, cdc *wire.Codec, decoder sdk.AccountDecoder) *cobra.Command { +func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder) *cobra.Command { return &cobra.Command{ Use: "account [address]", Short: "Query account balance", diff --git a/x/auth/context.go b/x/auth/context.go index b233f1e861..40fb177858 100644 --- a/x/auth/context.go +++ b/x/auth/context.go @@ -34,15 +34,15 @@ const ( ) // add the signers to the context -func WithSigners(ctx types.Context, accounts []types.Account) types.Context { +func WithSigners(ctx types.Context, accounts []Account) types.Context { return ctx.WithValue(contextKeySigners, accounts) } // get the signers from the context -func GetSigners(ctx types.Context) []types.Account { +func GetSigners(ctx types.Context) []Account { v := ctx.Value(contextKeySigners) if v == nil { - return []types.Account{} + return []Account{} } - return v.([]types.Account) + return v.([]Account) } diff --git a/x/auth/mapper.go b/x/auth/mapper.go index 3666f13b69..cdab2480e3 100644 --- a/x/auth/mapper.go +++ b/x/auth/mapper.go @@ -9,9 +9,6 @@ import ( crypto "github.com/tendermint/go-crypto" ) -var _ sdk.AccountMapper = (*AccountMapper)(nil) - -// Implements sdk.AccountMapper. // This AccountMapper encodes/decodes accounts using the // go-amino (binary) encoding/decoding library. type AccountMapper struct { @@ -19,8 +16,8 @@ type AccountMapper struct { // The (unexposed) key used to access the store from the Context. key sdk.StoreKey - // The prototypical sdk.Account concrete type. - proto sdk.Account + // The prototypical Account concrete type. + proto Account // The wire codec for binary encoding/decoding of accounts. cdc *wire.Codec @@ -29,7 +26,7 @@ type AccountMapper struct { // NewAccountMapper returns a new sdk.AccountMapper that // uses go-amino to (binary) encode and decode concrete sdk.Accounts. // nolint -func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto sdk.Account) AccountMapper { +func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto Account) AccountMapper { return AccountMapper{ key: key, proto: proto, @@ -38,14 +35,14 @@ func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto sdk.Account) Acco } // Implaements sdk.AccountMapper. -func (am AccountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.Address) sdk.Account { +func (am AccountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.Address) Account { acc := am.clonePrototype() acc.SetAddress(addr) return acc } // Implements sdk.AccountMapper. -func (am AccountMapper) GetAccount(ctx sdk.Context, addr sdk.Address) sdk.Account { +func (am AccountMapper) GetAccount(ctx sdk.Context, addr sdk.Address) Account { store := ctx.KVStore(am.key) bz := store.Get(addr) if bz == nil { @@ -56,7 +53,7 @@ func (am AccountMapper) GetAccount(ctx sdk.Context, addr sdk.Address) sdk.Accoun } // Implements sdk.AccountMapper. -func (am AccountMapper) SetAccount(ctx sdk.Context, acc sdk.Account) { +func (am AccountMapper) SetAccount(ctx sdk.Context, acc Account) { addr := acc.GetAddress() store := ctx.KVStore(am.key) bz := am.encodeAccount(acc) @@ -64,7 +61,7 @@ func (am AccountMapper) SetAccount(ctx sdk.Context, acc sdk.Account) { } // Implements sdk.AccountMapper. -func (am AccountMapper) IterateAccounts(ctx sdk.Context, process func(sdk.Account) (stop bool)) { +func (am AccountMapper) IterateAccounts(ctx sdk.Context, process func(Account) (stop bool)) { store := ctx.KVStore(am.key) iter := store.Iterator(nil, nil) for { @@ -89,7 +86,8 @@ func (am AccountMapper) GetPubKey(ctx sdk.Context, addr sdk.Address) (crypto.Pub return acc.GetPubKey(), nil } -func (am AccountMapper) setPubKey(ctx sdk.Context, addr sdk.Address, newPubKey crypto.PubKey) sdk.Error { +// Sets the PubKey of the account at address +func (am AccountMapper) SetPubKey(ctx sdk.Context, addr sdk.Address, newPubKey crypto.PubKey) sdk.Error { acc := am.GetAccount(ctx, addr) if acc == nil { return sdk.ErrUnknownAddress(addr.String()) @@ -122,7 +120,7 @@ func (am AccountMapper) setSequence(ctx sdk.Context, addr sdk.Address, newSequen // misc. // Creates a new struct (or pointer to struct) from am.proto. -func (am AccountMapper) clonePrototype() sdk.Account { +func (am AccountMapper) clonePrototype() Account { protoRt := reflect.TypeOf(am.proto) if protoRt.Kind() == reflect.Ptr { protoCrt := protoRt.Elem() @@ -130,7 +128,7 @@ func (am AccountMapper) clonePrototype() sdk.Account { panic("accountMapper requires a struct proto sdk.Account, or a pointer to one") } protoRv := reflect.New(protoCrt) - clone, ok := protoRv.Interface().(sdk.Account) + clone, ok := protoRv.Interface().(Account) if !ok { panic(fmt.Sprintf("accountMapper requires a proto sdk.Account, but %v doesn't implement sdk.Account", protoRt)) } @@ -138,14 +136,14 @@ func (am AccountMapper) clonePrototype() sdk.Account { } protoRv := reflect.New(protoRt).Elem() - clone, ok := protoRv.Interface().(sdk.Account) + clone, ok := protoRv.Interface().(Account) if !ok { panic(fmt.Sprintf("accountMapper requires a proto sdk.Account, but %v doesn't implement sdk.Account", protoRt)) } return clone } -func (am AccountMapper) encodeAccount(acc sdk.Account) []byte { +func (am AccountMapper) encodeAccount(acc Account) []byte { bz, err := am.cdc.MarshalBinaryBare(acc) if err != nil { panic(err) @@ -153,7 +151,7 @@ func (am AccountMapper) encodeAccount(acc sdk.Account) []byte { return bz } -func (am AccountMapper) decodeAccount(bz []byte) (acc sdk.Account) { +func (am AccountMapper) decodeAccount(bz []byte) (acc Account) { err := am.cdc.UnmarshalBinaryBare(bz, &acc) if err != nil { panic(err) diff --git a/x/auth/stdtx.go b/x/auth/stdtx.go new file mode 100644 index 0000000000..bc01b01490 --- /dev/null +++ b/x/auth/stdtx.go @@ -0,0 +1,131 @@ +package auth + +import ( + "encoding/json" + + sdk "github.com/cosmos/cosmos-sdk/types" + crypto "github.com/tendermint/go-crypto" +) + +var _ sdk.Tx = (*StdTx)(nil) + +// StdTx is a standard way to wrap a Msg with Fee and Signatures. +// NOTE: the first signature is the FeePayer (Signatures must not be nil). +type StdTx struct { + Msg sdk.Msg `json:"msg"` + Fee StdFee `json:"fee"` + Signatures []StdSignature `json:"signatures"` +} + +func NewStdTx(msg sdk.Msg, fee StdFee, sigs []StdSignature) StdTx { + return StdTx{ + Msg: msg, + Fee: fee, + Signatures: sigs, + } +} + +//nolint +func (tx StdTx) GetMsg() sdk.Msg { return tx.Msg } + +// Signatures returns the signature of signers who signed the Msg. +// CONTRACT: Length returned is same as length of +// pubkeys returned from MsgKeySigners, and the order +// matches. +// CONTRACT: If the signature is missing (ie the Msg is +// invalid), then the corresponding signature is +// .Empty(). +func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures } + +// FeePayer returns the address responsible for paying the fees +// for the transactions. It's the first address returned by msg.GetSigners(). +// If GetSigners() is empty, this panics. +func FeePayer(tx sdk.Tx) sdk.Address { + return tx.GetMsg().GetSigners()[0] +} + +//__________________________________________________________ + +// StdFee includes the amount of coins paid in fees and the maximum +// gas to be used by the transaction. The ratio yields an effective "gasprice", +// which must be above some miminum to be accepted into the mempool. +type StdFee struct { + Amount sdk.Coins `json:"amount"` + Gas int64 `json:"gas"` +} + +func NewStdFee(gas int64, amount ...sdk.Coin) StdFee { + return StdFee{ + Amount: amount, + Gas: gas, + } +} + +// fee bytes for signing later +func (fee StdFee) Bytes() []byte { + // normalize. XXX + // this is a sign of something ugly + // (in the lcd_test, client side its null, + // server side its []) + if len(fee.Amount) == 0 { + fee.Amount = sdk.Coins{} + } + bz, err := json.Marshal(fee) // TODO + if err != nil { + panic(err) + } + return bz +} + +//__________________________________________________________ + +// StdSignDoc is replay-prevention structure. +// It includes the result of msg.GetSignBytes(), +// as well as the ChainID (prevent cross chain replay) +// and the Sequence numbers for each signature (prevent +// inchain replay and enforce tx ordering per account). +type StdSignDoc struct { + ChainID string `json:"chain_id"` + Sequences []int64 `json:"sequences"` + FeeBytes []byte `json:"fee_bytes"` + MsgBytes []byte `json:"msg_bytes"` + AltBytes []byte `json:"alt_bytes"` +} + +// StdSignBytes returns the bytes to sign for a transaction. +// TODO: change the API to just take a chainID and StdTx ? +func StdSignBytes(chainID string, sequences []int64, fee StdFee, msg sdk.Msg) []byte { + bz, err := json.Marshal(StdSignDoc{ + ChainID: chainID, + Sequences: sequences, + FeeBytes: fee.Bytes(), + MsgBytes: msg.GetSignBytes(), + }) + if err != nil { + panic(err) + } + return bz +} + +// StdSignMsg is a convenience structure for passing along +// a Msg with the other requirements for a StdSignDoc before +// it is signed. For use in the CLI. +type StdSignMsg struct { + ChainID string + Sequences []int64 + Fee StdFee + Msg sdk.Msg + // XXX: Alt +} + +// get message bytes +func (msg StdSignMsg) Bytes() []byte { + return StdSignBytes(msg.ChainID, msg.Sequences, msg.Fee, msg.Msg) +} + +// Standard Signature +type StdSignature struct { + crypto.PubKey `json:"pub_key"` // optional + crypto.Signature `json:"signature"` + Sequence int64 `json:"sequence"` +} diff --git a/x/auth/wire.go b/x/auth/wire.go deleted file mode 100644 index 9db1b85cca..0000000000 --- a/x/auth/wire.go +++ /dev/null @@ -1,12 +0,0 @@ -package auth - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/wire" -) - -// Register concrete types on wire codec for default AppAccount -func RegisterWire(cdc *wire.Codec) { - cdc.RegisterInterface((*sdk.Account)(nil), nil) - cdc.RegisterConcrete(&BaseAccount{}, "auth/Account", nil) -} diff --git a/x/bank/keeper.go b/x/bank/keeper.go index 6ef73c68b6..b14da4d81f 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) const ( @@ -16,11 +17,11 @@ const ( // Keeper manages transfers between accounts type Keeper struct { - am sdk.AccountMapper + am auth.AccountMapper } // NewKeeper returns a new Keeper -func NewKeeper(am sdk.AccountMapper) Keeper { +func NewKeeper(am auth.AccountMapper) Keeper { return Keeper{am: am} } @@ -63,11 +64,11 @@ func (keeper Keeper) InputOutputCoins(ctx sdk.Context, inputs []Input, outputs [ // SendKeeper only allows transfers between accounts, without the possibility of creating coins type SendKeeper struct { - am sdk.AccountMapper + am auth.AccountMapper } // NewSendKeeper returns a new Keeper -func NewSendKeeper(am sdk.AccountMapper) SendKeeper { +func NewSendKeeper(am auth.AccountMapper) SendKeeper { return SendKeeper{am: am} } @@ -95,11 +96,11 @@ func (keeper SendKeeper) InputOutputCoins(ctx sdk.Context, inputs []Input, outpu // ViewKeeper only allows reading of balances type ViewKeeper struct { - am sdk.AccountMapper + am auth.AccountMapper } // NewViewKeeper returns a new Keeper -func NewViewKeeper(am sdk.AccountMapper) ViewKeeper { +func NewViewKeeper(am auth.AccountMapper) ViewKeeper { return ViewKeeper{am: am} } @@ -115,7 +116,7 @@ func (keeper ViewKeeper) HasCoins(ctx sdk.Context, addr sdk.Address, amt sdk.Coi //______________________________________________________________________________________________ -func getCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address) sdk.Coins { +func getCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address) sdk.Coins { ctx.GasMeter().ConsumeGas(costGetCoins, "getCoins") acc := am.GetAccount(ctx, addr) if acc == nil { @@ -124,7 +125,7 @@ func getCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address) sdk.Coins return acc.GetCoins() } -func setCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) sdk.Error { +func setCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk.Coins) sdk.Error { ctx.GasMeter().ConsumeGas(costSetCoins, "setCoins") acc := am.GetAccount(ctx, addr) if acc == nil { @@ -136,13 +137,13 @@ func setCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.C } // HasCoins returns whether or not an account has at least amt coins. -func hasCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) bool { +func hasCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk.Coins) bool { ctx.GasMeter().ConsumeGas(costHasCoins, "hasCoins") return getCoins(ctx, am, addr).IsGTE(amt) } // SubtractCoins subtracts amt from the coins at the addr. -func subtractCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { +func subtractCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { ctx.GasMeter().ConsumeGas(costSubtractCoins, "subtractCoins") oldCoins := getCoins(ctx, am, addr) newCoins := oldCoins.Minus(amt) @@ -155,7 +156,7 @@ func subtractCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt } // AddCoins adds amt to the coins at the addr. -func addCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { +func addCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { ctx.GasMeter().ConsumeGas(costAddCoins, "addCoins") oldCoins := getCoins(ctx, am, addr) newCoins := oldCoins.Plus(amt) @@ -169,7 +170,7 @@ func addCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.C // SendCoins moves coins from one account to another // NOTE: Make sure to revert state changes from tx on error -func sendCoins(ctx sdk.Context, am sdk.AccountMapper, fromAddr sdk.Address, toAddr sdk.Address, amt sdk.Coins) (sdk.Tags, sdk.Error) { +func sendCoins(ctx sdk.Context, am auth.AccountMapper, fromAddr sdk.Address, toAddr sdk.Address, amt sdk.Coins) (sdk.Tags, sdk.Error) { _, subTags, err := subtractCoins(ctx, am, fromAddr, amt) if err != nil { return nil, err @@ -185,7 +186,7 @@ func sendCoins(ctx sdk.Context, am sdk.AccountMapper, fromAddr sdk.Address, toAd // InputOutputCoins handles a list of inputs and outputs // NOTE: Make sure to revert state changes from tx on error -func inputOutputCoins(ctx sdk.Context, am sdk.AccountMapper, inputs []Input, outputs []Output) (sdk.Tags, sdk.Error) { +func inputOutputCoins(ctx sdk.Context, am auth.AccountMapper, inputs []Input, outputs []Output) (sdk.Tags, sdk.Error) { allTags := sdk.EmptyTags() for _, in := range inputs { diff --git a/x/auth/baseaccount.go b/x/baseaccount/baseaccount.go similarity index 90% rename from x/auth/baseaccount.go rename to x/baseaccount/baseaccount.go index ff907fc387..9701ac41dc 100644 --- a/x/auth/baseaccount.go +++ b/x/baseaccount/baseaccount.go @@ -1,18 +1,19 @@ -package auth +package baseaccount import ( "errors" - "github.com/tendermint/go-crypto" + crypto "github.com/tendermint/go-crypto" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) //----------------------------------------------------------- // BaseAccount -var _ sdk.Account = (*BaseAccount)(nil) +var _ auth.Account = (*BaseAccount)(nil) // BaseAccount - base account structure. // Extend this by embedding this in your AppAccount. @@ -82,7 +83,7 @@ func (acc *BaseAccount) SetSequence(seq int64) error { // Most users shouldn't use this, but this comes handy for tests. func RegisterBaseAccount(cdc *wire.Codec) { - cdc.RegisterInterface((*sdk.Account)(nil), nil) + cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterConcrete(&BaseAccount{}, "cosmos-sdk/BaseAccount", nil) wire.RegisterCrypto(cdc) } diff --git a/x/auth/baseaccount_test.go b/x/baseaccount/baseaccount_test.go similarity index 99% rename from x/auth/baseaccount_test.go rename to x/baseaccount/baseaccount_test.go index d3363e4fb0..ed1a322c2f 100644 --- a/x/auth/baseaccount_test.go +++ b/x/baseaccount/baseaccount_test.go @@ -1,4 +1,4 @@ -package auth +package baseaccount import ( "testing" diff --git a/x/auth/handler.go b/x/baseaccount/handler.go similarity index 58% rename from x/auth/handler.go rename to x/baseaccount/handler.go index 8a0e1061ae..46307c8818 100644 --- a/x/auth/handler.go +++ b/x/baseaccount/handler.go @@ -1,19 +1,20 @@ -package auth +package baseaccount import ( "reflect" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) -// NewHandler returns a handler for "auth" type messages. -func NewHandler(am AccountMapper) sdk.Handler { +// NewHandler returns a handler for "baseaccount" type messages. +func NewHandler(am auth.AccountMapper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case MsgChangeKey: return handleMsgChangeKey(ctx, am, msg) default: - errMsg := "Unrecognized auth Msg type: " + reflect.TypeOf(msg).Name() + errMsg := "Unrecognized baseaccount Msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() } } @@ -21,9 +22,9 @@ func NewHandler(am AccountMapper) sdk.Handler { // Handle MsgChangeKey // Should be very expensive, because once this happens, an account is un-prunable -func handleMsgChangeKey(ctx sdk.Context, am AccountMapper, msg MsgChangeKey) sdk.Result { +func handleMsgChangeKey(ctx sdk.Context, am auth.AccountMapper, msg MsgChangeKey) sdk.Result { - err := am.setPubKey(ctx, msg.Address, msg.NewPubKey) + err := am.SetPubKey(ctx, msg.Address, msg.NewPubKey) if err != nil { return err.Result() } diff --git a/x/auth/msgs.go b/x/baseaccount/msgs.go similarity index 87% rename from x/auth/msgs.go rename to x/baseaccount/msgs.go index 545b296e5b..f0319ac7fe 100644 --- a/x/auth/msgs.go +++ b/x/baseaccount/msgs.go @@ -1,11 +1,10 @@ -package auth +package baseaccount import ( "encoding/json" - "github.com/tendermint/go-crypto" - sdk "github.com/cosmos/cosmos-sdk/types" + crypto "github.com/tendermint/go-crypto" ) // MsgChangeKey - high level transaction of the auth module @@ -22,7 +21,7 @@ func NewMsgChangeKey(addr sdk.Address, pubkey crypto.PubKey) MsgChangeKey { } // Implements Msg. -func (msg MsgChangeKey) Type() string { return "auth" } +func (msg MsgChangeKey) Type() string { return "baseaccount" } // Implements Msg. func (msg MsgChangeKey) ValidateBasic() sdk.Error { diff --git a/x/auth/msgs_test.go b/x/baseaccount/msgs_test.go similarity index 97% rename from x/auth/msgs_test.go rename to x/baseaccount/msgs_test.go index 30c98b073b..46797fa0d8 100644 --- a/x/auth/msgs_test.go +++ b/x/baseaccount/msgs_test.go @@ -1,4 +1,4 @@ -package auth +package baseaccount import ( "testing" diff --git a/x/baseaccount/wire.go b/x/baseaccount/wire.go new file mode 100644 index 0000000000..4c77d1c72c --- /dev/null +++ b/x/baseaccount/wire.go @@ -0,0 +1,14 @@ +package baseaccount + +import ( + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" +) + +// Register concrete types on wire codec +func RegisterWire(cdc *wire.Codec) { + cdc.RegisterInterface((*auth.Account)(nil), nil) + cdc.RegisterConcrete(&BaseAccount{}, "baseaccount/BaseAccount", nil) + wire.RegisterCrypto(cdc) + cdc.RegisterConcrete(MsgChangeKey{}, "baseaccount/changekey", nil) +} diff --git a/x/stake/test_common.go b/x/stake/test_common.go index 2dac36069e..19487c5785 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -16,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/baseaccount" ) // dummy addresses used for testing @@ -72,8 +73,8 @@ func makeTestCodec() *wire.Codec { cdc.RegisterConcrete(MsgUnbond{}, "test/stake/Unbond", nil) // Register AppAccount - cdc.RegisterInterface((*sdk.Account)(nil), nil) - cdc.RegisterConcrete(&auth.BaseAccount{}, "test/stake/Account", nil) + cdc.RegisterInterface((*auth.Account)(nil), nil) + cdc.RegisterConcrete(&baseaccount.BaseAccount{}, "test/stake/Account", nil) wire.RegisterCrypto(cdc) return cdc @@ -91,7 +92,12 @@ func paramsNoInflation() Params { } // hogpodge of all sorts of input required for testing +<<<<<<< HEAD func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context, sdk.AccountMapper, Keeper) { +======= +func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context, auth.AccountMapper, Keeper) { + db := dbm.NewMemDB() +>>>>>>> in progress keyStake := sdk.NewKVStoreKey("stake") keyAcc := sdk.NewKVStoreKey("acc") @@ -105,9 +111,9 @@ func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil, log.NewNopLogger()) cdc := makeTestCodec() accountMapper := auth.NewAccountMapper( - cdc, // amino codec - keyAcc, // target store - &auth.BaseAccount{}, // prototype + cdc, // amino codec + keyMain, // target store + &baseaccount.BaseAccount{}, // prototype ) ck := bank.NewKeeper(accountMapper) keeper := NewKeeper(cdc, keyStake, ck, DefaultCodespace) From 56d1c48812ce44bbc9ea179ee727bbc01071a95a Mon Sep 17 00:00:00 2001 From: sunnya97 Date: Wed, 23 May 2018 19:47:33 -0700 Subject: [PATCH 14/21] in progress --- x/auth/client/rest/query.go | 7 ++++--- x/ibc/client/cli/relay.go | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index 52244fec9c..a60ce5cdb2 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -10,19 +10,20 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" - auth "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + "github.com/cosmos/cosmos-sdk/x/auth" + authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" ) // register REST routes func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, storeName string) { r.HandleFunc( "/accounts/{address}", - QueryAccountRequestHandlerFn(storeName, cdc, auth.GetAccountDecoder(cdc), ctx), + QueryAccountRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), ctx), ).Methods("GET") } // query accountREST Handler -func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder sdk.AccountDecoder, ctx context.CoreContext) http.HandlerFunc { +func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) addr := vars["address"] diff --git a/x/ibc/client/cli/relay.go b/x/ibc/client/cli/relay.go index 3a1e63a84a..caf96d60a4 100644 --- a/x/ibc/client/cli/relay.go +++ b/x/ibc/client/cli/relay.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/ibc" ) @@ -27,7 +28,7 @@ const ( type relayCommander struct { cdc *wire.Codec address sdk.Address - decoder sdk.AccountDecoder + decoder auth.AccountDecoder mainStore string ibcStore string accStore string From 5d7c3af1b8577f3df20ee00704398ca23f8c95c8 Mon Sep 17 00:00:00 2001 From: sunnya97 Date: Wed, 23 May 2018 22:09:01 -0700 Subject: [PATCH 15/21] works --- Gopkg.lock | 47 +--------- baseapp/baseapp_test.go | 15 ++-- client/lcd/lcd_test.go | 5 +- cmd/gaia/app/app.go | 7 +- cmd/gaia/app/app_test.go | 12 +-- cmd/gaia/app/genesis.go | 9 +- examples/basecoin/app/app.go | 10 +-- examples/basecoin/app/app_test.go | 12 +-- examples/basecoin/types/account.go | 6 +- examples/democoin/app/app.go | 8 +- examples/democoin/app/app_test.go | 16 ++-- examples/democoin/types/account.go | 6 +- .../democoin/x/simplestake/keeper_test.go | 7 +- examples/kvstore/tx.go | 3 +- mock/tx.go | 3 +- x/auth/account.go | 81 +++++++++++++++++ .../account_test.go} | 2 +- x/auth/ante.go | 2 +- x/auth/ante_test.go | 34 +++---- x/auth/context_test.go | 2 +- x/{baseaccount => auth}/handler.go | 7 +- x/{baseaccount => auth}/msgs.go | 4 +- x/{baseaccount => auth}/msgs_test.go | 2 +- types/tx_msg_test.go => x/auth/stdtx_test.go | 16 ++-- x/auth/wire.go | 12 +++ x/baseaccount/baseaccount.go | 89 ------------------- x/baseaccount/wire.go | 14 --- x/ibc/ibc_test.go | 4 +- x/stake/test_common.go | 9 +- 29 files changed, 197 insertions(+), 247 deletions(-) rename x/{baseaccount/baseaccount_test.go => auth/account_test.go} (99%) rename x/{baseaccount => auth}/handler.go (79%) rename x/{baseaccount => auth}/msgs.go (91%) rename x/{baseaccount => auth}/msgs_test.go (97%) rename types/tx_msg_test.go => x/auth/stdtx_test.go (70%) create mode 100644 x/auth/wire.go delete mode 100644 x/baseaccount/baseaccount.go delete mode 100644 x/baseaccount/wire.go diff --git a/Gopkg.lock b/Gopkg.lock index dcc57cab33..37a32820c2 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -13,51 +13,6 @@ packages = ["btcec"] revision = "1432d294a5b055c297457c25434efbf13384cc46" -[[projects]] - name = "github.com/cosmos/cosmos-sdk" - packages = [ - "baseapp", - "client", - "client/context", - "client/keys", - "client/lcd", - "client/rpc", - "client/tx", - "cmd/gaia/app", - "examples/basecoin/app", - "examples/basecoin/types", - "examples/democoin/app", - "examples/democoin/types", - "examples/democoin/x/cool", - "examples/democoin/x/cool/client/cli", - "examples/democoin/x/pow", - "examples/democoin/x/pow/client/cli", - "examples/democoin/x/simplestake", - "examples/democoin/x/simplestake/client/cli", - "examples/democoin/x/sketchy", - "mock", - "server", - "store", - "tests", - "types", - "version", - "wire", - "x/auth", - "x/auth/client/cli", - "x/auth/client/rest", - "x/bank", - "x/bank/client", - "x/bank/client/cli", - "x/bank/client/rest", - "x/ibc", - "x/ibc/client/cli", - "x/ibc/client/rest", - "x/stake", - "x/stake/client/cli" - ] - revision = "187be1a5df81de1fd71da9053102d3a4868ec979" - version = "v0.17.2" - [[projects]] name = "github.com/davecgh/go-spew" packages = ["spew"] @@ -502,6 +457,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "9b6ee069da61cf1815c332c5624e8af99b51ea72e2e9b91d780db92299598dcc" + inputs-digest = "7540d2ecdb5d7d5084ab4e6132e929bbd501bd6add3006d8f08a6b2c127e0c7d" solver-name = "gps-cdcl" solver-version = 1 diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 969a9f9add..61498b1b19 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -11,13 +11,14 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/abci/types" - "github.com/tendermint/go-crypto" + crypto "github.com/tendermint/go-crypto" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) func defaultLogger() log.Logger { @@ -446,12 +447,12 @@ type testUpdatePowerTx struct { const msgType = "testUpdatePowerTx" -func (tx testUpdatePowerTx) Type() string { return msgType } -func (tx testUpdatePowerTx) GetMsg() sdk.Msg { return tx } -func (tx testUpdatePowerTx) GetSignBytes() []byte { return nil } -func (tx testUpdatePowerTx) ValidateBasic() sdk.Error { return nil } -func (tx testUpdatePowerTx) GetSigners() []sdk.Address { return nil } -func (tx testUpdatePowerTx) GetSignatures() []sdk.StdSignature { return nil } +func (tx testUpdatePowerTx) Type() string { return msgType } +func (tx testUpdatePowerTx) GetMsg() sdk.Msg { return tx } +func (tx testUpdatePowerTx) GetSignBytes() []byte { return nil } +func (tx testUpdatePowerTx) ValidateBasic() sdk.Error { return nil } +func (tx testUpdatePowerTx) GetSigners() []sdk.Address { return nil } +func (tx testUpdatePowerTx) GetSignatures() []auth.StdSignature { return nil } func TestValidatorChange(t *testing.T) { diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 66a8a4085f..29b4ba1124 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -35,6 +35,7 @@ import ( btypes "github.com/cosmos/cosmos-sdk/examples/basecoin/types" tests "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) var ( @@ -436,11 +437,11 @@ func request(t *testing.T, port, method, path string, payload []byte) (*http.Res return res, string(output) } -func getAccount(t *testing.T, sendAddr string) sdk.Account { +func getAccount(t *testing.T, sendAddr string) auth.Account { // get the account to get the sequence res, body := request(t, port, "GET", "/accounts/"+sendAddr, nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - var acc sdk.Account + var acc auth.Account err := cdc.UnmarshalJSON([]byte(body), &acc) require.Nil(t, err) return acc diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index df4429ee25..b2f51498ba 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -14,7 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/baseaccount" "github.com/cosmos/cosmos-sdk/x/ibc" "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -63,8 +62,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { // define the accountMapper app.accountMapper = auth.NewAccountMapper( app.cdc, - app.keyAccount, // target store - &baseaccount.BaseAccount{}, // prototype + app.keyAccount, // target store + &auth.BaseAccount{}, // prototype ) // add handlers @@ -97,7 +96,7 @@ func MakeCodec() *wire.Codec { ibc.RegisterWire(cdc) bank.RegisterWire(cdc) stake.RegisterWire(cdc) - baseaccount.RegisterWire(cdc) + auth.RegisterWire(cdc) sdk.RegisterWire(cdc) wire.RegisterCrypto(cdc) return cdc diff --git a/cmd/gaia/app/app_test.go b/cmd/gaia/app/app_test.go index 42a56959ca..b6f1c9e03c 100644 --- a/cmd/gaia/app/app_test.go +++ b/cmd/gaia/app/app_test.go @@ -38,7 +38,7 @@ var ( coins = sdk.Coins{{"foocoin", 10}} halfCoins = sdk.Coins{{"foocoin", 5}} manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}} - fee = sdk.StdFee{ + fee = auth.StdFee{ sdk.Coins{{"foocoin", 0}}, 100000, } @@ -463,17 +463,17 @@ func CheckBalance(t *testing.T, gapp *GaiaApp, addr sdk.Address, balExpected str assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins())) } -func genTx(msg sdk.Msg, seq []int64, priv ...crypto.PrivKeyEd25519) sdk.StdTx { - sigs := make([]sdk.StdSignature, len(priv)) +func genTx(msg sdk.Msg, seq []int64, priv ...crypto.PrivKeyEd25519) auth.StdTx { + sigs := make([]auth.StdSignature, len(priv)) for i, p := range priv { - sigs[i] = sdk.StdSignature{ + sigs[i] = auth.StdSignature{ PubKey: p.PubKey(), - Signature: p.Sign(sdk.StdSignBytes(chainID, seq, fee, msg)), + Signature: p.Sign(auth.StdSignBytes(chainID, seq, fee, msg)), Sequence: seq[i], } } - return sdk.NewStdTx(msg, fee, sigs) + return auth.NewStdTx(msg, fee, sigs) } diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 6914ec4927..8cf45e84a2 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -13,7 +13,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/baseaccount" "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -29,7 +28,7 @@ type GenesisAccount struct { Coins sdk.Coins `json:"coins"` } -func NewGenesisAccount(acc *baseaccount.BaseAccount) GenesisAccount { +func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount { return GenesisAccount{ Address: acc.Address, Coins: acc.Coins, @@ -44,8 +43,8 @@ func NewGenesisAccountI(acc auth.Account) GenesisAccount { } // convert GenesisAccount to auth.BaseAccount -func (ga *GenesisAccount) ToAccount() (acc *baseaccount.BaseAccount) { - return &baseaccount.BaseAccount{ +func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { + return &auth.BaseAccount{ Address: ga.Address, Coins: ga.Coins.Sort(), } @@ -149,7 +148,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso } // create the genesis account, give'm few steaks and a buncha token with there name - accAuth := baseaccount.NewBaseAccountWithAddress(genTx.Address) + accAuth := auth.NewBaseAccountWithAddress(genTx.Address) accAuth.Coins = sdk.Coins{ {genTx.Name + "Token", 1000}, {"steak", freeFermionsAcc}, diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index b1a434fa2c..610a9e5525 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -35,7 +35,7 @@ type BasecoinApp struct { keyStake *sdk.KVStoreKey // Manage getting and setting accounts - accountMapper sdk.AccountMapper + accountMapper auth.AccountMapper coinKeeper bank.Keeper ibcMapper ibc.Mapper stakeKeeper stake.Keeper @@ -70,7 +70,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { // register message routes app.Router(). - AddRoute("auth", auth.NewHandler(app.accountMapper.(auth.AccountMapper))). + AddRoute("auth", auth.NewHandler(app.accountMapper)). AddRoute("bank", bank.NewHandler(app.coinKeeper)). AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)). AddRoute("stake", stake.NewHandler(app.stakeKeeper)) @@ -78,7 +78,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { // Initialize BaseApp. app.SetInitChainer(app.initChainer) app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.BurnFeeHandler)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper)) err := app.LoadLatestVersion(app.keyMain) if err != nil { cmn.Exit(err.Error()) @@ -96,7 +96,7 @@ func MakeCodec() *wire.Codec { ibc.RegisterWire(cdc) // register custom AppAccount - cdc.RegisterInterface((*sdk.Account)(nil), nil) + cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterConcrete(&types.AppAccount{}, "basecoin/Account", nil) return cdc } @@ -129,7 +129,7 @@ func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro // iterate to get the accounts accounts := []*types.GenesisAccount{} - appendAccount := func(acc sdk.Account) (stop bool) { + appendAccount := func(acc auth.Account) (stop bool) { account := &types.GenesisAccount{ Address: acc.GetAddress(), Coins: acc.GetCoins(), diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index d0b59f3313..e297288d3f 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -37,7 +37,7 @@ var ( coins = sdk.Coins{{"foocoin", 10}} halfCoins = sdk.Coins{{"foocoin", 5}} manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}} - fee = sdk.StdFee{ + fee = auth.StdFee{ sdk.Coins{{"foocoin", 0}}, 100000, } @@ -471,17 +471,17 @@ func TestIBCMsgs(t *testing.T) { SignCheckDeliver(t, bapp, receiveMsg, []int64{3}, false, priv1) } -func genTx(msg sdk.Msg, seq []int64, priv ...crypto.PrivKeyEd25519) sdk.StdTx { - sigs := make([]sdk.StdSignature, len(priv)) +func genTx(msg sdk.Msg, seq []int64, priv ...crypto.PrivKeyEd25519) auth.StdTx { + sigs := make([]auth.StdSignature, len(priv)) for i, p := range priv { - sigs[i] = sdk.StdSignature{ + sigs[i] = auth.StdSignature{ PubKey: p.PubKey(), - Signature: p.Sign(sdk.StdSignBytes(chainID, seq, fee, msg)), + Signature: p.Sign(auth.StdSignBytes(chainID, seq, fee, msg)), Sequence: seq[i], } } - return sdk.NewStdTx(msg, fee, sigs) + return auth.NewStdTx(msg, fee, sigs) } diff --git a/examples/basecoin/types/account.go b/examples/basecoin/types/account.go index e6eb5d7b46..223e0b9eb1 100644 --- a/examples/basecoin/types/account.go +++ b/examples/basecoin/types/account.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" ) -var _ sdk.Account = (*AppAccount)(nil) +var _ auth.Account = (*AppAccount)(nil) // Custom extensions for this application. This is just an example of // extending auth.BaseAccount with custom fields. @@ -23,8 +23,8 @@ func (acc AppAccount) GetName() string { return acc.Name } func (acc *AppAccount) SetName(name string) { acc.Name = name } // Get the AccountDecoder function for the custom AppAccount -func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder { - return func(accBytes []byte) (res sdk.Account, err error) { +func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder { + return func(accBytes []byte) (res auth.Account, err error) { if len(accBytes) == 0 { return nil, sdk.ErrTxDecode("accBytes are empty") } diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index 7c8250b189..9696630b6e 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -46,7 +46,7 @@ type DemocoinApp struct { stakeKeeper simplestake.Keeper // Manage getting and setting accounts - accountMapper sdk.AccountMapper + accountMapper auth.AccountMapper } func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp { @@ -89,7 +89,7 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp { // Initialize BaseApp. app.SetInitChainer(app.initChainerFn(app.coolKeeper, app.powKeeper)) app.MountStoresIAVL(app.capKeyMainStore, app.capKeyAccountStore, app.capKeyPowStore, app.capKeyIBCStore, app.capKeyStakingStore) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.BurnFeeHandler)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper)) err := app.LoadLatestVersion(app.capKeyMainStore) if err != nil { cmn.Exit(err.Error()) @@ -109,7 +109,7 @@ func MakeCodec() *wire.Codec { simplestake.RegisterWire(cdc) // Register AppAccount - cdc.RegisterInterface((*sdk.Account)(nil), nil) + cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterConcrete(&types.AppAccount{}, "democoin/Account", nil) return cdc } @@ -158,7 +158,7 @@ func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro // iterate to get the accounts accounts := []*types.GenesisAccount{} - appendAccount := func(acc sdk.Account) (stop bool) { + appendAccount := func(acc auth.Account) (stop bool) { account := &types.GenesisAccount{ Address: acc.GetAddress(), Coins: acc.GetCoins(), diff --git a/examples/democoin/app/app_test.go b/examples/democoin/app/app_test.go index b0f188f10b..e025c50627 100644 --- a/examples/democoin/app/app_test.go +++ b/examples/democoin/app/app_test.go @@ -31,7 +31,7 @@ var ( addr1 = priv1.PubKey().Address() addr2 = crypto.GenPrivKeyEd25519().PubKey().Address() coins = sdk.Coins{{"foocoin", 10}} - fee = sdk.StdFee{ + fee = auth.StdFee{ sdk.Coins{{"foocoin", 0}}, 1000000, } @@ -93,8 +93,8 @@ func TestMsgs(t *testing.T) { sequences := []int64{0} for i, m := range msgs { - sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, m.msg)) - tx := sdk.NewStdTx(m.msg, fee, []sdk.StdSignature{{ + sig := priv1.Sign(auth.StdSignBytes(chainID, sequences, fee, m.msg)) + tx := auth.NewStdTx(m.msg, fee, []auth.StdSignature{{ PubKey: priv1.PubKey(), Signature: sig, }}) @@ -194,8 +194,8 @@ func TestMsgSendWithAccounts(t *testing.T) { // Sign the tx sequences := []int64{0} - sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, sendMsg)) - tx := sdk.NewStdTx(sendMsg, fee, []sdk.StdSignature{{ + sig := priv1.Sign(auth.StdSignBytes(chainID, sequences, fee, sendMsg)) + tx := auth.NewStdTx(sendMsg, fee, []auth.StdSignature{{ PubKey: priv1.PubKey(), Signature: sig, }}) @@ -227,7 +227,7 @@ func TestMsgSendWithAccounts(t *testing.T) { // resigning the tx with the bumped sequence should work sequences = []int64{1} - sig = priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, tx.Msg)) + sig = priv1.Sign(auth.StdSignBytes(chainID, sequences, fee, tx.Msg)) tx.Signatures[0].Signature = sig res = bapp.Deliver(tx) assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) @@ -394,9 +394,9 @@ func TestHandler(t *testing.T) { func SignCheckDeliver(t *testing.T, bapp *DemocoinApp, msg sdk.Msg, seq int64, expPass bool) { // Sign the tx - tx := sdk.NewStdTx(msg, fee, []sdk.StdSignature{{ + tx := auth.NewStdTx(msg, fee, []auth.StdSignature{{ PubKey: priv1.PubKey(), - Signature: priv1.Sign(sdk.StdSignBytes(chainID, []int64{seq}, fee, msg)), + Signature: priv1.Sign(auth.StdSignBytes(chainID, []int64{seq}, fee, msg)), Sequence: seq, }}) diff --git a/examples/democoin/types/account.go b/examples/democoin/types/account.go index 8a744229ad..211cf3c416 100644 --- a/examples/democoin/types/account.go +++ b/examples/democoin/types/account.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/examples/democoin/x/pow" ) -var _ sdk.Account = (*AppAccount)(nil) +var _ auth.Account = (*AppAccount)(nil) // Custom extensions for this application. This is just an example of // extending auth.BaseAccount with custom fields. @@ -26,8 +26,8 @@ func (acc AppAccount) GetName() string { return acc.Name } func (acc *AppAccount) SetName(name string) { acc.Name = name } // Get the AccountDecoder function for the custom AppAccount -func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder { - return func(accBytes []byte) (res sdk.Account, err error) { +func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder { + return func(accBytes []byte) (res auth.Account, err error) { if len(accBytes) == 0 { return nil, sdk.ErrTxDecode("accBytes are empty") } diff --git a/examples/democoin/x/simplestake/keeper_test.go b/examples/democoin/x/simplestake/keeper_test.go index 302a2e58b6..515c19cc59 100644 --- a/examples/democoin/x/simplestake/keeper_test.go +++ b/examples/democoin/x/simplestake/keeper_test.go @@ -31,10 +31,13 @@ func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey) { } func TestKeeperGetSet(t *testing.T) { - ms, _, capKey := setupMultiStore() + ms, authKey, capKey := setupMultiStore() + cdc := wire.NewCodec() + auth.RegisterBaseAccount(cdc) ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) - stakeKeeper := NewKeeper(capKey, bank.NewKeeper(nil), DefaultCodespace) + accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) + stakeKeeper := NewKeeper(capKey, bank.NewKeeper(accountMapper), DefaultCodespace) addr := sdk.Address([]byte("some-address")) bi := stakeKeeper.getBondInfo(ctx, addr) diff --git a/examples/kvstore/tx.go b/examples/kvstore/tx.go index 12bce0736f..fa32d93bfb 100644 --- a/examples/kvstore/tx.go +++ b/examples/kvstore/tx.go @@ -4,6 +4,7 @@ import ( "bytes" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) // An sdk.Tx which is its own sdk.Msg. @@ -34,7 +35,7 @@ func (tx kvstoreTx) GetSigners() []sdk.Address { return nil } -func (tx kvstoreTx) GetSignatures() []sdk.StdSignature { +func (tx kvstoreTx) GetSignatures() []auth.StdSignature { return nil } diff --git a/mock/tx.go b/mock/tx.go index 81dea45718..bd437f2d08 100644 --- a/mock/tx.go +++ b/mock/tx.go @@ -6,6 +6,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) // An sdk.Tx which is its own sdk.Msg. @@ -47,7 +48,7 @@ func (tx kvstoreTx) GetSigners() []sdk.Address { return nil } -func (tx kvstoreTx) GetSignatures() []sdk.StdSignature { +func (tx kvstoreTx) GetSignatures() []auth.StdSignature { return nil } diff --git a/x/auth/account.go b/x/auth/account.go index 28366467aa..0ae72a8a64 100644 --- a/x/auth/account.go +++ b/x/auth/account.go @@ -1,7 +1,10 @@ package auth import ( + "errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" crypto "github.com/tendermint/go-crypto" ) @@ -23,3 +26,81 @@ type Account interface { // AccountDecoder unmarshals account bytes type AccountDecoder func(accountBytes []byte) (Account, error) + +//----------------------------------------------------------- +// BaseAccount + +var _ Account = (*BaseAccount)(nil) + +// BaseAccount - base account structure. +// Extend this by embedding this in your AppAccount. +// See the examples/basecoin/types/account.go for an example. +type BaseAccount struct { + Address sdk.Address `json:"address"` + Coins sdk.Coins `json:"coins"` + PubKey crypto.PubKey `json:"public_key"` + Sequence int64 `json:"sequence"` +} + +func NewBaseAccountWithAddress(addr sdk.Address) BaseAccount { + return BaseAccount{ + Address: addr, + } +} + +// Implements sdk.Account. +func (acc BaseAccount) GetAddress() sdk.Address { + return acc.Address +} + +// Implements sdk.Account. +func (acc *BaseAccount) SetAddress(addr sdk.Address) error { + if len(acc.Address) != 0 { + return errors.New("cannot override BaseAccount address") + } + acc.Address = addr + return nil +} + +// Implements sdk.Account. +func (acc BaseAccount) GetPubKey() crypto.PubKey { + return acc.PubKey +} + +// Implements sdk.Account. +func (acc *BaseAccount) SetPubKey(pubKey crypto.PubKey) error { + acc.PubKey = pubKey + return nil +} + +// Implements sdk.Account. +func (acc *BaseAccount) GetCoins() sdk.Coins { + return acc.Coins +} + +// Implements sdk.Account. +func (acc *BaseAccount) SetCoins(coins sdk.Coins) error { + acc.Coins = coins + return nil +} + +// Implements sdk.Account. +func (acc *BaseAccount) GetSequence() int64 { + return acc.Sequence +} + +// Implements sdk.Account. +func (acc *BaseAccount) SetSequence(seq int64) error { + acc.Sequence = seq + return nil +} + +//---------------------------------------- +// Wire + +// Most users shouldn't use this, but this comes handy for tests. +func RegisterBaseAccount(cdc *wire.Codec) { + cdc.RegisterInterface((*Account)(nil), nil) + cdc.RegisterConcrete(&BaseAccount{}, "cosmos-sdk/BaseAccount", nil) + wire.RegisterCrypto(cdc) +} diff --git a/x/baseaccount/baseaccount_test.go b/x/auth/account_test.go similarity index 99% rename from x/baseaccount/baseaccount_test.go rename to x/auth/account_test.go index ed1a322c2f..d3363e4fb0 100644 --- a/x/baseaccount/baseaccount_test.go +++ b/x/auth/account_test.go @@ -1,4 +1,4 @@ -package baseaccount +package auth import ( "testing" diff --git a/x/auth/ante.go b/x/auth/ante.go index d57c8558ef..c92a87641a 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -24,7 +24,7 @@ func NewAnteHandler(am AccountMapper) sdk.AnteHandler { // This AnteHandler requires Txs to be StdTxs stdTx, ok := tx.(StdTx) if !ok { - return ctx, sdk.ErrInternal("tx must be sdk.StdTx").Result(), true + return ctx, sdk.ErrInternal("tx must be StdTx").Result(), true } // Assert that there are signatures. diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index ec296b12be..fcde2b464b 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -17,8 +17,8 @@ func newTestMsg(addrs ...sdk.Address) *sdk.TestMsg { return sdk.NewTestMsg(addrs...) } -func newStdFee() sdk.StdFee { - return sdk.NewStdFee(100, +func newStdFee() StdFee { + return NewStdFee(100, sdk.Coin{"atom", 150}, ) } @@ -52,17 +52,17 @@ func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), result.Code) } -func newTestTx(ctx sdk.Context, msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, fee sdk.StdFee) sdk.Tx { - signBytes := sdk.StdSignBytes(ctx.ChainID(), seqs, fee, msg) +func newTestTx(ctx sdk.Context, msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, fee StdFee) sdk.Tx { + signBytes := StdSignBytes(ctx.ChainID(), seqs, fee, msg) return newTestTxWithSignBytes(msg, privs, seqs, fee, signBytes) } -func newTestTxWithSignBytes(msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, fee sdk.StdFee, signBytes []byte) sdk.Tx { - sigs := make([]sdk.StdSignature, len(privs)) +func newTestTxWithSignBytes(msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, fee StdFee, signBytes []byte) sdk.Tx { + sigs := make([]StdSignature, len(privs)) for i, priv := range privs { - sigs[i] = sdk.StdSignature{PubKey: priv.PubKey(), Signature: priv.Sign(signBytes), Sequence: seqs[i]} + sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: priv.Sign(signBytes), Sequence: seqs[i]} } - tx := sdk.NewStdTx(msg, fee, sigs) + tx := NewStdTx(msg, fee, sigs) return tx } @@ -73,7 +73,7 @@ func TestAnteHandlerSigErrors(t *testing.T) { cdc := wire.NewCodec() RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) - anteHandler := NewAnteHandler(mapper, BurnFeeHandler) + anteHandler := NewAnteHandler(mapper) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses @@ -114,7 +114,7 @@ func TestAnteHandlerSequences(t *testing.T) { cdc := wire.NewCodec() RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) - anteHandler := NewAnteHandler(mapper, BurnFeeHandler) + anteHandler := NewAnteHandler(mapper) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses @@ -180,7 +180,7 @@ func TestAnteHandlerFees(t *testing.T) { cdc := wire.NewCodec() RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) - anteHandler := NewAnteHandler(mapper, BurnFeeHandler) + anteHandler := NewAnteHandler(mapper) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses @@ -194,7 +194,7 @@ func TestAnteHandlerFees(t *testing.T) { var tx sdk.Tx msg := newTestMsg(addr1) privs, seqs := []crypto.PrivKey{priv1}, []int64{0} - fee := sdk.NewStdFee(100, + fee := NewStdFee(100, sdk.Coin{"atom", 150}, ) @@ -217,7 +217,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { cdc := wire.NewCodec() RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) - anteHandler := NewAnteHandler(mapper, BurnFeeHandler) + anteHandler := NewAnteHandler(mapper) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses @@ -252,7 +252,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { cases := []struct { chainID string seqs []int64 - fee sdk.StdFee + fee StdFee msg sdk.Msg code sdk.CodeType }{ @@ -268,7 +268,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { for _, cs := range cases { tx := newTestTxWithSignBytes( msg, privs, seqs, fee, - sdk.StdSignBytes(cs.chainID, cs.seqs, cs.fee, cs.msg), + StdSignBytes(cs.chainID, cs.seqs, cs.fee, cs.msg), ) checkInvalidTx(t, anteHandler, ctx, tx, cs.code) } @@ -292,7 +292,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) { cdc := wire.NewCodec() RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) - anteHandler := NewAnteHandler(mapper, BurnFeeHandler) + anteHandler := NewAnteHandler(mapper) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses @@ -322,7 +322,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) { // test public key not found msg = newTestMsg(addr2) tx = newTestTx(ctx, msg, privs, seqs, fee) - sigs := tx.GetSignatures() + sigs := tx.(StdTx).GetSignatures() sigs[0].PubKey = nil checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey) diff --git a/x/auth/context_test.go b/x/auth/context_test.go index 89e318e0a1..e1db131679 100644 --- a/x/auth/context_test.go +++ b/x/auth/context_test.go @@ -26,7 +26,7 @@ func TestContextWithSigners(t *testing.T) { signers := GetSigners(ctx) assert.Equal(t, 0, len(signers)) - ctx2 := WithSigners(ctx, []sdk.Account{&acc1, &acc2}) + ctx2 := WithSigners(ctx, []Account{&acc1, &acc2}) // original context is unchanged signers = GetSigners(ctx) diff --git a/x/baseaccount/handler.go b/x/auth/handler.go similarity index 79% rename from x/baseaccount/handler.go rename to x/auth/handler.go index 46307c8818..764c6f7a28 100644 --- a/x/baseaccount/handler.go +++ b/x/auth/handler.go @@ -1,14 +1,13 @@ -package baseaccount +package auth import ( "reflect" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" ) // NewHandler returns a handler for "baseaccount" type messages. -func NewHandler(am auth.AccountMapper) sdk.Handler { +func NewHandler(am AccountMapper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case MsgChangeKey: @@ -22,7 +21,7 @@ func NewHandler(am auth.AccountMapper) sdk.Handler { // Handle MsgChangeKey // Should be very expensive, because once this happens, an account is un-prunable -func handleMsgChangeKey(ctx sdk.Context, am auth.AccountMapper, msg MsgChangeKey) sdk.Result { +func handleMsgChangeKey(ctx sdk.Context, am AccountMapper, msg MsgChangeKey) sdk.Result { err := am.SetPubKey(ctx, msg.Address, msg.NewPubKey) if err != nil { diff --git a/x/baseaccount/msgs.go b/x/auth/msgs.go similarity index 91% rename from x/baseaccount/msgs.go rename to x/auth/msgs.go index f0319ac7fe..c449b837b1 100644 --- a/x/baseaccount/msgs.go +++ b/x/auth/msgs.go @@ -1,4 +1,4 @@ -package baseaccount +package auth import ( "encoding/json" @@ -21,7 +21,7 @@ func NewMsgChangeKey(addr sdk.Address, pubkey crypto.PubKey) MsgChangeKey { } // Implements Msg. -func (msg MsgChangeKey) Type() string { return "baseaccount" } +func (msg MsgChangeKey) Type() string { return "auth" } // Implements Msg. func (msg MsgChangeKey) ValidateBasic() sdk.Error { diff --git a/x/baseaccount/msgs_test.go b/x/auth/msgs_test.go similarity index 97% rename from x/baseaccount/msgs_test.go rename to x/auth/msgs_test.go index 46797fa0d8..30c98b073b 100644 --- a/x/baseaccount/msgs_test.go +++ b/x/auth/msgs_test.go @@ -1,4 +1,4 @@ -package baseaccount +package auth import ( "testing" diff --git a/types/tx_msg_test.go b/x/auth/stdtx_test.go similarity index 70% rename from types/tx_msg_test.go rename to x/auth/stdtx_test.go index f72cdea26e..412b37c20d 100644 --- a/types/tx_msg_test.go +++ b/x/auth/stdtx_test.go @@ -1,4 +1,4 @@ -package types +package auth import ( "testing" @@ -6,18 +6,20 @@ import ( "github.com/stretchr/testify/assert" crypto "github.com/tendermint/go-crypto" + + sdk "github.com/cosmos/cosmos-sdk/types" ) -func newStdFee() StdFee { - return NewStdFee(100, - Coin{"atom", 150}, - ) -} +// func newStdFee() StdFee { +// return NewStdFee(100, +// Coin{"atom", 150}, +// ) +// } func TestStdTx(t *testing.T) { priv := crypto.GenPrivKeyEd25519() addr := priv.PubKey().Address() - msg := NewTestMsg(addr) + msg := sdk.NewTestMsg(addr) fee := newStdFee() sigs := []StdSignature{} diff --git a/x/auth/wire.go b/x/auth/wire.go new file mode 100644 index 0000000000..42b34b96d5 --- /dev/null +++ b/x/auth/wire.go @@ -0,0 +1,12 @@ +package auth + +import ( + "github.com/cosmos/cosmos-sdk/wire" +) + +// Register concrete types on wire codec for default AppAccount +func RegisterWire(cdc *wire.Codec) { + cdc.RegisterInterface((*Account)(nil), nil) + cdc.RegisterConcrete(&BaseAccount{}, "auth/Account", nil) + cdc.RegisterConcrete(MsgChangeKey{}, "auth/ChangeKey", nil) +} diff --git a/x/baseaccount/baseaccount.go b/x/baseaccount/baseaccount.go deleted file mode 100644 index 9701ac41dc..0000000000 --- a/x/baseaccount/baseaccount.go +++ /dev/null @@ -1,89 +0,0 @@ -package baseaccount - -import ( - "errors" - - crypto "github.com/tendermint/go-crypto" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/wire" - "github.com/cosmos/cosmos-sdk/x/auth" -) - -//----------------------------------------------------------- -// BaseAccount - -var _ auth.Account = (*BaseAccount)(nil) - -// BaseAccount - base account structure. -// Extend this by embedding this in your AppAccount. -// See the examples/basecoin/types/account.go for an example. -type BaseAccount struct { - Address sdk.Address `json:"address"` - Coins sdk.Coins `json:"coins"` - PubKey crypto.PubKey `json:"public_key"` - Sequence int64 `json:"sequence"` -} - -func NewBaseAccountWithAddress(addr sdk.Address) BaseAccount { - return BaseAccount{ - Address: addr, - } -} - -// Implements sdk.Account. -func (acc BaseAccount) GetAddress() sdk.Address { - return acc.Address -} - -// Implements sdk.Account. -func (acc *BaseAccount) SetAddress(addr sdk.Address) error { - if len(acc.Address) != 0 { - return errors.New("cannot override BaseAccount address") - } - acc.Address = addr - return nil -} - -// Implements sdk.Account. -func (acc BaseAccount) GetPubKey() crypto.PubKey { - return acc.PubKey -} - -// Implements sdk.Account. -func (acc *BaseAccount) SetPubKey(pubKey crypto.PubKey) error { - acc.PubKey = pubKey - return nil -} - -// Implements sdk.Account. -func (acc *BaseAccount) GetCoins() sdk.Coins { - return acc.Coins -} - -// Implements sdk.Account. -func (acc *BaseAccount) SetCoins(coins sdk.Coins) error { - acc.Coins = coins - return nil -} - -// Implements sdk.Account. -func (acc *BaseAccount) GetSequence() int64 { - return acc.Sequence -} - -// Implements sdk.Account. -func (acc *BaseAccount) SetSequence(seq int64) error { - acc.Sequence = seq - return nil -} - -//---------------------------------------- -// Wire - -// Most users shouldn't use this, but this comes handy for tests. -func RegisterBaseAccount(cdc *wire.Codec) { - cdc.RegisterInterface((*auth.Account)(nil), nil) - cdc.RegisterConcrete(&BaseAccount{}, "cosmos-sdk/BaseAccount", nil) - wire.RegisterCrypto(cdc) -} diff --git a/x/baseaccount/wire.go b/x/baseaccount/wire.go deleted file mode 100644 index 4c77d1c72c..0000000000 --- a/x/baseaccount/wire.go +++ /dev/null @@ -1,14 +0,0 @@ -package baseaccount - -import ( - "github.com/cosmos/cosmos-sdk/wire" - "github.com/cosmos/cosmos-sdk/x/auth" -) - -// Register concrete types on wire codec -func RegisterWire(cdc *wire.Codec) { - cdc.RegisterInterface((*auth.Account)(nil), nil) - cdc.RegisterConcrete(&BaseAccount{}, "baseaccount/BaseAccount", nil) - wire.RegisterCrypto(cdc) - cdc.RegisterConcrete(MsgChangeKey{}, "baseaccount/changekey", nil) -} diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index 60cc59bad9..e13df4f8dd 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" abci "github.com/tendermint/abci/types" - "github.com/tendermint/go-crypto" + crypto "github.com/tendermint/go-crypto" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -49,7 +49,7 @@ func makeCodec() *wire.Codec { cdc.RegisterConcrete(IBCReceiveMsg{}, "test/ibc/IBCReceiveMsg", nil) // Register AppAccount - cdc.RegisterInterface((*sdk.Account)(nil), nil) + cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterConcrete(&auth.BaseAccount{}, "test/ibc/Account", nil) wire.RegisterCrypto(cdc) diff --git a/x/stake/test_common.go b/x/stake/test_common.go index e75faaf01a..b7a5152c09 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -16,7 +16,6 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/baseaccount" ) // dummy addresses used for testing @@ -74,7 +73,7 @@ func makeTestCodec() *wire.Codec { // Register AppAccount cdc.RegisterInterface((*auth.Account)(nil), nil) - cdc.RegisterConcrete(&baseaccount.BaseAccount{}, "test/stake/Account", nil) + cdc.RegisterConcrete(&auth.BaseAccount{}, "test/stake/Account", nil) wire.RegisterCrypto(cdc) return cdc @@ -107,9 +106,9 @@ func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil, log.NewNopLogger()) cdc := makeTestCodec() accountMapper := auth.NewAccountMapper( - cdc, // amino codec - keyAcc, // target store - &baseaccount.BaseAccount{}, // prototype + cdc, // amino codec + keyAcc, // target store + &auth.BaseAccount{}, // prototype ) ck := bank.NewKeeper(accountMapper) keeper := NewKeeper(cdc, keyStake, ck, DefaultCodespace) From 157720836225e9d67b02edc1ee742d4c533a4402 Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Thu, 24 May 2018 14:03:22 -0300 Subject: [PATCH 16/21] fix typos --- examples/examples.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/examples.md b/examples/examples.md index 7d8665ca62..55db606c4c 100644 --- a/examples/examples.md +++ b/examples/examples.md @@ -40,7 +40,7 @@ basecoind version They should read something like `0.17.1-5d18d5f`, but the versions will be constantly updating so don't worry if your version is higher that 0.17.1. That's a good thing. -Note that you can always check help in the terminal by running `basecli -h` or `basecoind -h`. It is good to check these out if you are stuck, because updates to the code base might slighty change the commands, and you might find the correct command in there. +Note that you can always check help in the terminal by running `basecli -h` or `basecoind -h`. It is good to check these out if you are stuck, because updates to the code base might slightly change the commands, and you might find the correct command in there. Let's start by initializing the basecoind daemon. Run the command @@ -131,7 +131,7 @@ Flag Descriptions: - `name` is the name you gave your key - `mycoin` is the name of the token for this basecoin demo, initialized in the genesis.json file - `sequence` is a tally of how many transactions have been made by this account. Since this is the first tx on this account, it is 0 -- `chain-id` is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/gensis.json` +- `chain-id` is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/genesis.json` Now if we check bobs account, it should have `10000 mycoin`. You can do so by running : @@ -161,7 +161,7 @@ Notice that the sequence is now 1, since we have already recorded bobs 1st trans basecli tx ``` -It will return the details of the transaction hash, such as how many coins were send and to which address, and on what block it occured. +It will return the details of the transaction hash, such as how many coins were send and to which address, and on what block it occurred. That is the basic implementation of basecoin! From d3bdb09ffce1a6cb2ed941f3d614b8999e5c423b Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Fri, 25 May 2018 20:29:40 -0700 Subject: [PATCH 17/21] passes, needs tests --- cmd/gaia/app/app.go | 11 +++--- examples/basecoin/app/app.go | 11 +++--- examples/democoin/app/app.go | 13 ++++---- x/auth/ante.go | 8 +++-- x/auth/ante_test.go | 25 ++++++++------ x/auth/context_test.go | 2 +- x/auth/feekeeper.go | 65 ++++++++++++++++++++++++++++++++++++ x/auth/mapper_test.go | 8 +++-- 8 files changed, 111 insertions(+), 32 deletions(-) create mode 100644 x/auth/feekeeper.go diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index b2f51498ba..dbecada004 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -40,10 +40,11 @@ type GaiaApp struct { keyStake *sdk.KVStoreKey // Manage getting and setting accounts - accountMapper auth.AccountMapper - coinKeeper bank.Keeper - ibcMapper ibc.Mapper - stakeKeeper stake.Keeper + accountMapper auth.AccountMapper + feeCollectionKeeper auth.FeeCollectionKeeper + coinKeeper bank.Keeper + ibcMapper ibc.Mapper + stakeKeeper stake.Keeper } func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { @@ -81,7 +82,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { app.SetInitChainer(app.initChainer) app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper)) app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) err := app.LoadLatestVersion(app.keyMain) if err != nil { cmn.Exit(err.Error()) diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index 610a9e5525..086fa32b36 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -35,10 +35,11 @@ type BasecoinApp struct { keyStake *sdk.KVStoreKey // Manage getting and setting accounts - accountMapper auth.AccountMapper - coinKeeper bank.Keeper - ibcMapper ibc.Mapper - stakeKeeper stake.Keeper + accountMapper auth.AccountMapper + feeCollectionKeeper auth.FeeCollectionKeeper + coinKeeper bank.Keeper + ibcMapper ibc.Mapper + stakeKeeper stake.Keeper } func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { @@ -78,7 +79,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { // Initialize BaseApp. app.SetInitChainer(app.initChainer) app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) err := app.LoadLatestVersion(app.keyMain) if err != nil { cmn.Exit(err.Error()) diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index 9696630b6e..2075a64da0 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -39,11 +39,12 @@ type DemocoinApp struct { capKeyStakingStore *sdk.KVStoreKey // keepers - coinKeeper bank.Keeper - coolKeeper cool.Keeper - powKeeper pow.Keeper - ibcMapper ibc.Mapper - stakeKeeper simplestake.Keeper + feeCollectionKeeper auth.FeeCollectionKeeper + coinKeeper bank.Keeper + coolKeeper cool.Keeper + powKeeper pow.Keeper + ibcMapper ibc.Mapper + stakeKeeper simplestake.Keeper // Manage getting and setting accounts accountMapper auth.AccountMapper @@ -89,7 +90,7 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp { // Initialize BaseApp. app.SetInitChainer(app.initChainerFn(app.coolKeeper, app.powKeeper)) app.MountStoresIAVL(app.capKeyMainStore, app.capKeyAccountStore, app.capKeyPowStore, app.capKeyIBCStore, app.capKeyStakingStore) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) err := app.LoadLatestVersion(app.capKeyMainStore) if err != nil { cmn.Exit(err.Error()) diff --git a/x/auth/ante.go b/x/auth/ante.go index c92a87641a..21f8df0fbd 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -9,13 +9,14 @@ import ( ) const ( - verifyCost = 100 + deductFeesCost sdk.Gas = 10 + verifyCost = 100 ) // NewAnteHandler returns an AnteHandler that checks // and increments sequence numbers, checks signatures, // and deducts fees from the first signer. -func NewAnteHandler(am AccountMapper) sdk.AnteHandler { +func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler { return func( ctx sdk.Context, tx sdk.Tx, @@ -77,7 +78,10 @@ func NewAnteHandler(am AccountMapper) sdk.AnteHandler { if i == 0 { // TODO: min fee if !fee.Amount.IsZero() { + ctx.GasMeter().ConsumeGas(deductFeesCost, "deductFees") signerAcc, res = deductFees(signerAcc, fee) + fck.addCollectedFees(ctx, fee.Amount) + if !res.IsOK() { return ctx, res, true } diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index fcde2b464b..e21be8f16f 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -69,11 +69,12 @@ func newTestTxWithSignBytes(msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, f // Test various error cases in the AnteHandler control flow. func TestAnteHandlerSigErrors(t *testing.T) { // setup - ms, capKey := setupMultiStore() + ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) - anteHandler := NewAnteHandler(mapper) + feeCollector := NewFeeCollectionKeeper(cdc, capKey2) + anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses @@ -110,11 +111,12 @@ func TestAnteHandlerSigErrors(t *testing.T) { // Test logic around sequence checking with one signer and many signers. func TestAnteHandlerSequences(t *testing.T) { // setup - ms, capKey := setupMultiStore() + ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) - anteHandler := NewAnteHandler(mapper) + feeCollector := NewFeeCollectionKeeper(cdc, capKey2) + anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses @@ -176,11 +178,12 @@ func TestAnteHandlerSequences(t *testing.T) { // Test logic around fee deduction. func TestAnteHandlerFees(t *testing.T) { // setup - ms, capKey := setupMultiStore() + ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) - anteHandler := NewAnteHandler(mapper) + feeCollector := NewFeeCollectionKeeper(cdc, capKey2) + anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses @@ -213,11 +216,12 @@ func TestAnteHandlerFees(t *testing.T) { func TestAnteHandlerBadSignBytes(t *testing.T) { // setup - ms, capKey := setupMultiStore() + ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) - anteHandler := NewAnteHandler(mapper) + feeCollector := NewFeeCollectionKeeper(cdc, capKey2) + anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses @@ -288,11 +292,12 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { func TestAnteHandlerSetPubKey(t *testing.T) { // setup - ms, capKey := setupMultiStore() + ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) - anteHandler := NewAnteHandler(mapper) + feeCollector := NewFeeCollectionKeeper(cdc, capKey2) + anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses diff --git a/x/auth/context_test.go b/x/auth/context_test.go index e1db131679..a93de44d0c 100644 --- a/x/auth/context_test.go +++ b/x/auth/context_test.go @@ -12,7 +12,7 @@ import ( ) func TestContextWithSigners(t *testing.T) { - ms, _ := setupMultiStore() + ms, _, _ := setupMultiStore() ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) _, _, addr1 := keyPubAddr() diff --git a/x/auth/feekeeper.go b/x/auth/feekeeper.go new file mode 100644 index 0000000000..0828fb3652 --- /dev/null +++ b/x/auth/feekeeper.go @@ -0,0 +1,65 @@ +package auth + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + wire "github.com/cosmos/cosmos-sdk/wire" +) + +// This FeeCollectionKeeper handles collection of fees in the anteHandler +// and setting of MinFees for different fee tokens +type FeeCollectionKeeper struct { + + // The (unexposed) key used to access the fee store from the Context. + key sdk.StoreKey + + // The wire codec for binary encoding/decoding of accounts. + cdc *wire.Codec +} + +// NewFeeKeeper returns a new FeeKeeper +func NewFeeCollectionKeeper(cdc *wire.Codec, key sdk.StoreKey) FeeCollectionKeeper { + return FeeCollectionKeeper{ + key: key, + cdc: cdc, + } +} + +// Adds to Collected Fee Pool +func (fck FeeCollectionKeeper) GetCollectedFees(ctx sdk.Context) sdk.Coins { + store := ctx.KVStore(fck.key) + bz := store.Get([]byte("collectedFees")) + if bz == nil { + return sdk.Coins{} + } + + feePool := &(sdk.Coins{}) + err := fck.cdc.UnmarshalBinary(bz, feePool) + if err != nil { + panic("should not happen") + } + return *feePool +} + +// Sets to Collected Fee Pool +func (fck FeeCollectionKeeper) setCollectedFees(ctx sdk.Context, coins sdk.Coins) { + bz, err := fck.cdc.MarshalBinary(coins) + if err != nil { + panic("should not happen") + } + + store := ctx.KVStore(fck.key) + store.Set([]byte("collectedFees"), bz) +} + +// Adds to Collected Fee Pool +func (fck FeeCollectionKeeper) addCollectedFees(ctx sdk.Context, coins sdk.Coins) sdk.Coins { + newCoins := fck.GetCollectedFees(ctx).Plus(coins) + fck.setCollectedFees(ctx, newCoins) + + return newCoins +} + +// Clears the collected Fee Pool +func (fck FeeCollectionKeeper) ClearCollectedFees(ctx sdk.Context) { + fck.setCollectedFees(ctx, sdk.Coins{}) +} diff --git a/x/auth/mapper_test.go b/x/auth/mapper_test.go index cdd418990a..7f6397069a 100644 --- a/x/auth/mapper_test.go +++ b/x/auth/mapper_test.go @@ -14,17 +14,19 @@ import ( wire "github.com/cosmos/cosmos-sdk/wire" ) -func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey) { +func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey) { db := dbm.NewMemDB() capKey := sdk.NewKVStoreKey("capkey") + capKey2 := sdk.NewKVStoreKey("capkey2") ms := store.NewCommitMultiStore(db) ms.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(capKey2, sdk.StoreTypeIAVL, db) ms.LoadLatestVersion() - return ms, capKey + return ms, capKey, capKey2 } func TestAccountMapperGetSet(t *testing.T) { - ms, capKey := setupMultiStore() + ms, capKey, _ := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) From f81a70b3150606c2d24ed028f2605990500eb208 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Fri, 25 May 2018 20:48:27 -0700 Subject: [PATCH 18/21] added keeper tests --- x/auth/feekeeper_test.go | 75 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 x/auth/feekeeper_test.go diff --git a/x/auth/feekeeper_test.go b/x/auth/feekeeper_test.go new file mode 100644 index 0000000000..2f1ffc59bc --- /dev/null +++ b/x/auth/feekeeper_test.go @@ -0,0 +1,75 @@ +package auth + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + abci "github.com/tendermint/abci/types" + "github.com/tendermint/tmlibs/log" + + sdk "github.com/cosmos/cosmos-sdk/types" + wire "github.com/cosmos/cosmos-sdk/wire" +) + +var ( + emptyCoins = sdk.Coins{} + oneCoin = sdk.Coins{{"foocoin", 1}} + twoCoins = sdk.Coins{{"foocoin", 2}} +) + +func TestFeeCollectionKeeperGetSet(t *testing.T) { + ms, _, capKey2 := setupMultiStore() + cdc := wire.NewCodec() + + // make context and keeper + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + fck := NewFeeCollectionKeeper(cdc, capKey2) + + // no coins initially + currFees := fck.GetCollectedFees(ctx) + assert.True(t, currFees.IsEqual(emptyCoins)) + + // set feeCollection to oneCoin + fck.setCollectedFees(ctx, oneCoin) + + // check that it is equal to oneCoin + assert.True(t, fck.GetCollectedFees(ctx).IsEqual(oneCoin)) +} + +func TestFeeCollectionKeeperAdd(t *testing.T) { + ms, _, capKey2 := setupMultiStore() + cdc := wire.NewCodec() + + // make context and keeper + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + fck := NewFeeCollectionKeeper(cdc, capKey2) + + // no coins initially + assert.True(t, fck.GetCollectedFees(ctx).IsEqual(emptyCoins)) + + // add oneCoin and check that pool is now oneCoin + fck.addCollectedFees(ctx, oneCoin) + assert.True(t, fck.GetCollectedFees(ctx).IsEqual(oneCoin)) + + // add oneCoin again and check that pool is now twoCoins + fck.addCollectedFees(ctx, oneCoin) + assert.True(t, fck.GetCollectedFees(ctx).IsEqual(twoCoins)) +} + +func TestFeeCollectionKeeperClear(t *testing.T) { + ms, _, capKey2 := setupMultiStore() + cdc := wire.NewCodec() + + // make context and keeper + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + fck := NewFeeCollectionKeeper(cdc, capKey2) + + // set coins initially + fck.setCollectedFees(ctx, twoCoins) + assert.True(t, fck.GetCollectedFees(ctx).IsEqual(twoCoins)) + + // clear fees and see that pool is now empty + fck.ClearCollectedFees(ctx) + assert.True(t, fck.GetCollectedFees(ctx).IsEqual(emptyCoins)) +} From 4f6c77d8cba765f8f31125c3c753ed86efc88d5d Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Fri, 25 May 2018 21:10:09 -0700 Subject: [PATCH 19/21] antehandler tests --- x/auth/ante.go | 3 +-- x/auth/ante_test.go | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/x/auth/ante.go b/x/auth/ante.go index 21f8df0fbd..9663bcfe45 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -80,11 +80,10 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler { if !fee.Amount.IsZero() { ctx.GasMeter().ConsumeGas(deductFeesCost, "deductFees") signerAcc, res = deductFees(signerAcc, fee) - fck.addCollectedFees(ctx, fee.Amount) - if !res.IsOK() { return ctx, res, true } + fck.addCollectedFees(ctx, fee.Amount) } } diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index e21be8f16f..b7f22e5d54 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -209,9 +209,13 @@ func TestAnteHandlerFees(t *testing.T) { mapper.SetAccount(ctx, acc1) checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInsufficientFunds) + assert.True(t, feeCollector.GetCollectedFees(ctx).IsEqual(emptyCoins)) + acc1.SetCoins(sdk.Coins{{"atom", 150}}) mapper.SetAccount(ctx, acc1) checkValidTx(t, anteHandler, ctx, tx) + + assert.True(t, feeCollector.GetCollectedFees(ctx).IsEqual(sdk.Coins{{"atom", 150}})) } func TestAnteHandlerBadSignBytes(t *testing.T) { From bf02cdcf974c2f22b7b61e18483a48ea63a6d43f Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Fri, 25 May 2018 21:14:49 -0700 Subject: [PATCH 20/21] address Chris review --- x/auth/feekeeper.go | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/x/auth/feekeeper.go b/x/auth/feekeeper.go index 0828fb3652..3e03a81aa2 100644 --- a/x/auth/feekeeper.go +++ b/x/auth/feekeeper.go @@ -5,6 +5,10 @@ import ( wire "github.com/cosmos/cosmos-sdk/wire" ) +var ( + collectedFeesKey = []byte("collectedFees") +) + // This FeeCollectionKeeper handles collection of fees in the anteHandler // and setting of MinFees for different fee tokens type FeeCollectionKeeper struct { @@ -27,28 +31,21 @@ func NewFeeCollectionKeeper(cdc *wire.Codec, key sdk.StoreKey) FeeCollectionKeep // Adds to Collected Fee Pool func (fck FeeCollectionKeeper) GetCollectedFees(ctx sdk.Context) sdk.Coins { store := ctx.KVStore(fck.key) - bz := store.Get([]byte("collectedFees")) + bz := store.Get(collectedFeesKey) if bz == nil { return sdk.Coins{} } feePool := &(sdk.Coins{}) - err := fck.cdc.UnmarshalBinary(bz, feePool) - if err != nil { - panic("should not happen") - } + fck.cdc.MustUnmarshalBinary(bz, feePool) return *feePool } // Sets to Collected Fee Pool func (fck FeeCollectionKeeper) setCollectedFees(ctx sdk.Context, coins sdk.Coins) { - bz, err := fck.cdc.MarshalBinary(coins) - if err != nil { - panic("should not happen") - } - + bz := fck.cdc.MustMarshalBinary(coins) store := ctx.KVStore(fck.key) - store.Set([]byte("collectedFees"), bz) + store.Set(collectedFeesKey, bz) } // Adds to Collected Fee Pool From 92356b7d9be1b63d764073fe9843264fba556047 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 26 May 2018 04:36:05 -0400 Subject: [PATCH 21/21] changelog update --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73f5e5f880..19c50d56e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ ## 0.18.1 +BREAKING CHANGES + +* [x/auth] move stuff specific to auth anteHandler to the auth module rather than the types folder. This includes: + * StdTx (and its related stuff i.e. StdSignDoc, etc) + * StdFee + * StdSignature + * Account interface + * Related to this organization, I also: +* [x/auth] got rid of AccountMapper interface (in favor of the struct already in auth module) +* [x/auth] removed the FeeHandler function from the AnteHandler, Replaced with FeeKeeper +* [x/auth] Removed GetSignatures() from Tx interface (as different Tx styles might use something different than StdSignature) + BUG FIXES * auto-sequencing transactions correctly * query sequence via account store