Skip to content
This repository has been archived by the owner on Oct 7, 2020. It is now read-only.

Add stateful checkTx #276

Merged
merged 27 commits into from
Oct 16, 2017
Merged

Add stateful checkTx #276

merged 27 commits into from
Oct 16, 2017

Conversation

adrianbrink
Copy link

@adrianbrink adrianbrink commented Aug 19, 2017

  • add tests
  • double check the logic in go-ethereum for validateTx and update it accordingly

@codecov
Copy link

codecov bot commented Aug 19, 2017

Codecov Report

Merging #276 into develop will increase coverage by 1.86%.
The diff coverage is 55.55%.

Impacted file tree graph

@@             Coverage Diff             @@
##           develop     #276      +/-   ##
===========================================
+ Coverage    24.91%   26.77%   +1.86%     
===========================================
  Files           11       11              
  Lines          578      605      +27     
===========================================
+ Hits           144      162      +18     
- Misses         410      417       +7     
- Partials        24       26       +2
Impacted Files Coverage Δ
ethereum/backend.go 0% <ø> (ø) ⬆️
ethereum/txs.go 0% <0%> (ø) ⬆️
app/app.go 42.26% <58.13%> (+4.93%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9518a4d...7af08f8. Read the comment docs.

@odeke-em
Copy link
Contributor

@adrianbrink could you please educate me on the benefit from using a cached state for this purpose other than the normal benefits of using a cached copy of something(avoid extraneous lookup)?
However, I figure that for Ethereum, the state is continually changing so we'd rather always query the current copy.

@adrianbrink
Copy link
Author

The purpose of a cachedState here is that it allows us to send multiple TXs from the same account in a single block.

When I send a transaction J from account A, I increase the nonce from x to x+1. When Ethermint receives a transaction in CheckTx it checks that this condition is met, however it doesn't update any state so it always check against the state from the last block.
Let's say I send another transaction G from account A in the same block. I dutifully increase the nonce from x+1 to x+2. When Ethermint receives transaction G in CheckTx it will return an error, since the nonce isn't strictly increasing. This time the nonce jumped by 2 instead of 1.

Another reason is that with transaction H I might create a new account B. This account won't show up in the state that checkTx sees until the next block is created. However it is perfectly valid to send a transaction from account B in the same block, which won't work without state, since Ethermint currently thinks that account B doesn't exist.

If we have cached state all these use cases work.

app/app.go Outdated
@@ -207,6 +218,10 @@ func (app *EthermintApplication) validateTx(tx *ethTypes.Transaction) abciTypes.
AppendLog(core.ErrInvalidSender.Error())
}

// Update ether balances
currentState.SubBalance(from, tx.Value())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about subtracting gas fees ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these should also probably go after the checks for having enough.

app/app_test.go Outdated
@@ -132,7 +132,6 @@ func TestBumpingNonces(t *testing.T) {
stack.Stop() // nolint: errcheck
}

// TestMultipleTxOneAcc sends multiple TXs from the same account in the same block
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why lose the comment ?

app/app_test.go Outdated
stack, err := makeTestSystemNode(tempDatadir, addresses, mockclient)
// Test transaction from Acc1 to new Acc2 and then from Acc2 to another address
// in the same block
func TestFromAccToAcc(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice. did we check this fails without the rest of this PR ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -164,6 +173,11 @@ func (app *EthermintApplication) Commit() abciTypes.Result {
app.logger.Error("Error getting latest ethereum state", "err", err) // nolint: errcheck
return abciTypes.ErrInternalError.AppendLog(err.Error())
}
state, err := app.getCurrentState()
if err != nil {
app.logger.Error("Error getting latest state", "err", err) // nolint: errcheck
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does it take for this to err? do we need to catch it properly?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could happen if the underlying ethereum state gets corrupted.

We might want to abort here.

For now it only affects the checktx state though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

presumably state will be nil if there is an error and the call to Copy below will panic. So we should instead catch that and return an InternalError result so Tendermint knows something went wrong, logs the error, and halts

app/app.go Outdated
backend: backend,
rpcClient: client,
getCurrentState: backend.Ethereum().BlockChain().State,
cacheState: state.Copy(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maybe call it checkTxState, to emphasize that it's not for deliverTx caching.

app/app.go Outdated
from, err := ethTypes.Sender(signer, tx)
if err != nil {
return abciTypes.ErrBaseInvalidSignature.
AppendLog(core.ErrInvalidSender.Error())
}

// Heuristic limit, reject transactions over 32KB to prevent DOS attacks
if tx.Size() > 32*1024 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a const declared above, at least.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 32KB? This seems to break from Ethereum...

app/app.go Outdated
return abciTypes.ErrBaseInvalidInput.
SetLog(core.ErrNegativeValue.Error())
// Check for nonce errors
if currentState.GetNonce(from) > tx.Nonce() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nonce needs to be strictly incrementing by 1.

Copy link
Author

@adrianbrink adrianbrink Aug 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ethereum itself doesn't currently do that.

What is the benefit of doing it our way?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://ethereum.stackexchange.com/questions/2808/what-happens-when-a-transaction-nonce-is-too-high

See that Ethereum blocks still require nonces to be strictly incrementing by 1, even if there is no "ErrNonceTooHigh" error, due to the way the mempool works in Ethereum. (nonces that are too high are kept in the mempool for a while).

We should just use this error instead: https://github.com/tendermint/abci/blob/master/types/types.proto#L15

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future reference:

For a transaction to be valid it needs to have the same nonce as the account that sends it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this check if we just check for equality directly below ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we don't. I removed it.

app/app.go Outdated
// Update ether balances
// amount + gasprice * gaslimit
currentState.SubBalance(from, tx.Cost())
currentState.AddBalance(*tx.To(), tx.Value())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nonce should be incremented as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we test this nonce issue?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added it on top of the file TestIncrementingNonces.

app/app_test.go Outdated
@@ -49,10 +49,12 @@ func (mc *MockClient) Call(method string, params map[string]interface{}, result
switch method {
case "status":
result = &ctypes.ResultStatus{}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kinda strange to have blank spaces here.

app/app_test.go Outdated
// 1. put Acc1 and Acc2 to genesis with some amounts (X)
// 2. transfer 10 amount from Acc1 to Acc2
// 3. in the same block transfer from Acc2 to another Acc all his amounts (X+10)
func TestFromAccToAcc2(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot of repeated code between this and the one above it.
(I think) we should refactor the tests to pull out the common components, and also create a new test that ensures that two checkTxs where the second has the wrong nonce (e.g. too high or too low) will fail.

@@ -13,6 +13,6 @@
"gasLimit": "0x8000000",
"alloc": {
"0x7eff122b94897ea5b0e2a9abf47b86337fafebdc": { "balance": "10000000000000000000000000000000000" },
"0xc6713982649D9284ff56c32655a9ECcCDA78422A": { "balance": "10000000000000000000000000000000000" }
"0xc6713982649D9284ff56c32655a9ECcCDA78422A": { "balance": "10000000000000000000000000000000000" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some spacing issue, not aligned with the line above this.

Copy link
Contributor

@jaekwon jaekwon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost done, please address these issues!

@adrianbrink adrianbrink changed the title Add stateful checkTx WIP: Add stateful checkTx Aug 24, 2017
@adrianbrink
Copy link
Author

I refactored the app_test.go file, so that it is much cleaner now. The setup is now being done in test local functions as well as the teardown. It uses some functional magic to handle the teardown of test cases. I'm a big fan of this approach.

@odeke-em I would appreciate a review :-)

@@ -0,0 +1,3 @@
# TODO

* Document performance numbers for Tendermint and Ethermint and write a blog post about it
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can just be an issue, no? TODO files in a repo are unnecessary IMO ... it confuses what there is to do with issues

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alright

Tendermint RPC lib seems broken
@CLAassistant
Copy link

CLAassistant commented Oct 12, 2017

CLA assistant check
All committers have signed the CLA.

@adrianbrink adrianbrink merged commit ace6c40 into develop Oct 16, 2017
@adrianbrink adrianbrink deleted the feature/checktx branch October 16, 2017 08:34
adrianbrink pushed a commit that referenced this pull request Oct 22, 2017
* Add stateful checkTx

* Tests for stateful checktx

* Mirror validateTx logic from tx_pool.go. Move checkTxState updates

* Move transaction size limit into const. Remove uneeded fmt import

* Enable nonces to be strictly increasing

* Extract all directory setup into functional style tests

This change removes the duplicated code to setup temporary directories
for each test.
Now all code is grouped in the setupTestCase() function
instead of being littered around all the test cases.
There are no side effects of this.

* Refactor app_test.go to remove the duplicated code

The tests where getting unwieldy since they duplicated a lot of code.
With the new setup it is much easier to create new test cases, since the
setup and tear-down are handled nicely.

There are no side effects.

* Add test case for non-incremental nonces

This test case checks that transactions have to have strictly increasing
nonces. It tests by sending a transaction with nonce 0, and then tries
to send a transaction with nonce 2. The second transaction should fail,
since it is not strictly increasing.

Some of the error descriptions have changed, but no one should be
matching for a specific error string.

* Refactor tests and RPC library

This change is the last refactor of the app_tests and was needed for
clarity.

Also, it upgrades everything to use a typed RPC client instead of
passing strings to get to raw endpoints.

* Add check whether it's contract creation

* Update Changelog

Signed-off-by: Adrian Brink <[email protected]>
adrianbrink pushed a commit that referenced this pull request Oct 22, 2017
* Add stateful checkTx

* Tests for stateful checktx

* Mirror validateTx logic from tx_pool.go. Move checkTxState updates

* Move transaction size limit into const. Remove uneeded fmt import

* Enable nonces to be strictly increasing

* Extract all directory setup into functional style tests

This change removes the duplicated code to setup temporary directories
for each test.
Now all code is grouped in the setupTestCase() function
instead of being littered around all the test cases.
There are no side effects of this.

* Refactor app_test.go to remove the duplicated code

The tests where getting unwieldy since they duplicated a lot of code.
With the new setup it is much easier to create new test cases, since the
setup and tear-down are handled nicely.

There are no side effects.

* Add test case for non-incremental nonces

This test case checks that transactions have to have strictly increasing
nonces. It tests by sending a transaction with nonce 0, and then tries
to send a transaction with nonce 2. The second transaction should fail,
since it is not strictly increasing.

Some of the error descriptions have changed, but no one should be
matching for a specific error string.

* Refactor tests and RPC library

This change is the last refactor of the app_tests and was needed for
clarity.

Also, it upgrades everything to use a typed RPC client instead of
passing strings to get to raw endpoints.

* Add check whether it's contract creation

* Update Changelog

Signed-off-by: Adrian Brink <[email protected]>
adrianbrink pushed a commit that referenced this pull request Oct 22, 2017
* Add stateful checkTx

* Tests for stateful checktx

* Mirror validateTx logic from tx_pool.go. Move checkTxState updates

* Move transaction size limit into const. Remove uneeded fmt import

* Enable nonces to be strictly increasing

* Extract all directory setup into functional style tests

This change removes the duplicated code to setup temporary directories
for each test.
Now all code is grouped in the setupTestCase() function
instead of being littered around all the test cases.
There are no side effects of this.

* Refactor app_test.go to remove the duplicated code

The tests where getting unwieldy since they duplicated a lot of code.
With the new setup it is much easier to create new test cases, since the
setup and tear-down are handled nicely.

There are no side effects.

* Add test case for non-incremental nonces

This test case checks that transactions have to have strictly increasing
nonces. It tests by sending a transaction with nonce 0, and then tries
to send a transaction with nonce 2. The second transaction should fail,
since it is not strictly increasing.

Some of the error descriptions have changed, but no one should be
matching for a specific error string.

* Refactor tests and RPC library

This change is the last refactor of the app_tests and was needed for
clarity.

Also, it upgrades everything to use a typed RPC client instead of
passing strings to get to raw endpoints.

* Add check whether it's contract creation

* Update Changelog

Signed-off-by: Adrian Brink <[email protected]>
adrianbrink pushed a commit that referenced this pull request Oct 22, 2017
* Add stateful checkTx

* Tests for stateful checktx

* Mirror validateTx logic from tx_pool.go. Move
checkTxState updates

* Move transaction size limit into const. Remove
uneeded fmt import

* Enable nonces to be strictly increasing

* Extract all directory setup into functional
style tests

This change removes the duplicated code to setup
temporary directories for each test.
Now all code is grouped in the setupTestCase()
function instead of being littered around all
the test cases. There are no side effects of this.

* Refactor app_test.go to remove the duplicated
code

The tests where getting unwieldy since they
duplicated a lot of code.
With the new setup it is much easier to create
new test cases, since the setup and tear-down
are handled nicely.

There are no side effects.

* Add test case for non-incremental nonces

This test case checks that transactions have to
have strictly increasing nonces. It tests by
sending a transaction with nonce 0, and then tries
to send a transaction with nonce 2. The second
transaction should fail, since it is not strictly
increasing.

Some of the error descriptions have changed, but
no one should be matching for a specific error
string.

* Refactor tests and RPC library

This change is the last refactor of the app_tests
and was needed for clarity.

Also, it upgrades everything to use a typed RPC
client instead of passing strings to get to raw
endpoints.

* Add check whether it's contract creation

* Update Changelog

Signed-off-by: Adrian Brink <[email protected]>
adrianbrink pushed a commit that referenced this pull request Oct 22, 2017
* Add stateful checkTx

* Tests for stateful checktx

* Mirror validateTx logic from tx_pool.go.
Move checkTxState updates

* Move transaction size limit into const.
Remove uneeded fmt import

* Enable nonces to be strictly increasing

* Extract all directory setup into functional
style tests

This change removes the duplicated code to
setup temporary directories for each test.
Now all code is grouped in the setupTestCase()
function instead of being littered around all
the test cases. There are no side effects of
this.

* Refactor app_test.go to remove the
duplicated code

The tests where getting unwieldy since they
duplicated a lot of code. With the new setup
it is much easier to create new test cases,
since the setup and tear-down are handled
nicely.

There are no side effects.

* Add test case for non-incremental nonces

This test case checks that transactions have
to have strictly increasing nonces. It tests
by sending a transaction with nonce 0, and
then tries to send a transaction with nonce 2.
The second transaction should fail, since it
is not strictly increasing.

Some of the error descriptions have changed,
but no one should be matching for a specific
error string.

* Refactor tests and RPC library

This change is the last refactor of the
app_tests and was needed for clarity.

Also, it upgrades everything to use a typed
RPC client instead of passing strings to get
to raw endpoints.

* Add check whether it's contract creation

* Update Changelog

Signed-off-by: Adrian Brink <[email protected]>
adrianbrink pushed a commit that referenced this pull request Oct 22, 2017
* Add stateful checkTx

* Tests for stateful checktx

* Mirror validateTx logic from tx_pool.go.
Move checkTxState updates

* Move transaction size limit into const.
Remove uneeded fmt import

* Enable nonces to be strictly increasing

* Extract all directory setup into functional
style tests

This change removes the duplicated code to
setup temporary directories for each test.
Now all code is grouped in the setupTestCase()
function instead of being littered around
all the test cases. There are no side effects
of this.

* Refactor app_test.go to remove the
duplicated code

The tests where getting unwieldy since they
duplicated a lot of code. With the new setup
it is much easier to create new test cases,
since the setup and tear-down are handled nicely.

There are no side effects.

* Add test case for non-incremental nonces

This test case checks that transactions have
to have strictly increasing nonces. It tests
by sending a transaction with nonce 0, and then
tries to send a transaction with nonce 2. The
second transaction should fail, since it is not
strictly increasing.

Some of the error descriptions have changed,
but no one should be matching for a specific
error string.

* Refactor tests and RPC library

This change is the last refactor of the app_tests
and was needed for clarity.

Also, it upgrades everything to use a typed
RPC client instead of passing strings to
get to raw endpoints.

* Add check whether it's contract creation

* Update Changelog

Signed-off-by: Adrian Brink <[email protected]>
@zramsay zramsay mentioned this pull request Oct 24, 2017
i-norden pushed a commit to vulcanize/old_ethermint that referenced this pull request Aug 31, 2020
* update rpc tests

* cleanup

* add log assertion to getTransacionReceipt

* fix queurier_test

* address comment
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants