Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement EIP1559 Fee Market + EIP3198 BaseFee #1148

Merged
merged 86 commits into from
May 19, 2021
Merged

Implement EIP1559 Fee Market + EIP3198 BaseFee #1148

merged 86 commits into from
May 19, 2021

Conversation

jochem-brouwer
Copy link
Member

@jochem-brouwer jochem-brouwer commented Mar 14, 2021

This PR implements EIP 1559.

@codecov
Copy link

codecov bot commented Mar 14, 2021

Codecov Report

Merging #1148 (99cb89f) into master (4d3edaa) will decrease coverage by 1.95%.
The diff coverage is 83.20%.

Impacted file tree graph

Flag Coverage Δ
block 82.51% <75.36%> (-0.42%) ⬇️
blockchain 84.36% <93.10%> (+0.19%) ⬆️
client 84.70% <75.00%> (+0.11%) ⬆️
common 88.12% <100.00%> (+0.04%) ⬆️
devp2p 84.21% <66.66%> (-0.07%) ⬇️
ethash 82.08% <ø> (ø)
tx 88.74% <88.17%> (-0.09%) ⬇️
vm 80.87% <71.11%> (-5.90%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

@holgerd77
Copy link
Member

@jochem-brouwer cool, great that you gave this a start! 😄 👍 🎉

Yeah, it will very much make sense to further abstract here. Let's please give it a cut here, maybe you've got some time during the day and jump on a quick call (let me know when in chat)?

It actually get's hyper-tricky here. I guess the main problem is that the concept of inheritance just doesn't work well with this very abstract typed transaction EIP concept where a tx - theoretically - could contain anything. This might work for now - also e.g. regarding the question what is currently contained in BaseTransaction, but this is rather out of "randomness", since the feature set is just for this current set of typed transactions randomly fitting.

But one can already see where this leads to: in EIP-1559 there is e.g. no gasPrice and -whop - the whole BaseTransaction gets somewhat invalid from an API PoV. If there will be another tx type - e.g. with a new signature theme removing the v,r,s values - whop - base transaction respectively the whole inheritance chain will break again.

Not sure if this overloads us for now: but I at least theoretically wonder if e.g. some kind of module concept (gas module, signature module, access list module, eventually serialization module) might serve us better here and will be more future proof.

And a base transaction (or however it's called) might contain the information what kind of modules are activated, like so:

class BaseTransaction {
 
  modules: {
    gas: 'EIP1559',
    accessLists: true,
    signature: 'ECDSA', // future
    serialization: 'RLP',
  }

Something like this would also allow us to cleaner react in third-party code (VM, Block,...) to features available. The current approach will otherwise further down the road lead to a conditional hell like either always uncleanly just request for some thought-to-be-active properties (if (tx.gasPrice) { // do something... }) or (not better) adding to an ever growing chain of tx types (if (typeof tx in [AccessListTx, EIP1559Tx,... ]). All not really scaling.

Again, let's just jump on the call sometime. If we do this later the day eventually the others want to join as well.

@holgerd77
Copy link
Member

For reference: Base fee tests in Besu

@holgerd77
Copy link
Member

Nethermind EIP-1559 implementation: NethermindEth/nethermind#2341

@jochem-brouwer
Copy link
Member Author

Rebased this one

@jochem-brouwer
Copy link
Member Author

Yeah this design is getting rather complex already, I can fix this build error but the idea I got in mind might not be a really great design - will take a look at the other implementations first to get some inspiration here.

@holgerd77
Copy link
Member

@jochem-brouwer yeah, this is really tricky to answer and what level we want/need to refactor the whole library for this. In doubt just put this aside for now for a couple of days as some suggestion 😋 , sometimes this helps as well and we can pick this question up on our call and discuss together. If you would have alternatively some time for #1132 that would e.g. also be cool if we get this going a bit again. 😄

@jochem-brouwer
Copy link
Member Author

Okay, added some very basic VM tests, but at this point I cannot continue until I have more test data. I will probably create some very simple EIP1559 tests to just see that it produces something (so I can sign a transaction for instance), but I cannot be sure if we are correct.

@jochem-brouwer
Copy link
Member Author

Rebased upon master.

@jochem-brouwer
Copy link
Member Author

Ok great, tests pass, now trying to connect to Aleut.

@jochem-brouwer
Copy link
Member Author

We are only downloading 1 block at a time since for some reason the bootnode either sends invalid data, or we have a bug in devp2p. It tries to decode RLP message bodies where RLP states it should decode ~33k bytes, but the block is actually only 1023 bytes long. (The message body itself is 1024 bytes).

@jochem-brouwer
Copy link
Member Author

jochem-brouwer commented Apr 26, 2021

Ok, this commit 8c112f0 fixes the consensus bug at block 55. The problem had nothing to do with EIP1559, it had to do with runBlock/runTx in VM: runBlock originally fed runTx an edited block than the block which is actually being ran; the gasUsed field is changed and used to keep track of the cumulative gas used. This commit is a hotfix and might be changed in the future (probably removing editing the block and just passing along the block which is actually being ran in the context).

We should add a test to ensure that clique blocks with txs pay the right miner, which is not tested in VM currently.

There also still is a problem with the Nethermind bootnode. If we request more than 1 block (might be ok to request 2 or 3) - lets say the original 50, then we get a RLP decode error on devp2p.

With these fixes we can sync up to block 3704:

ERROR [04-26|22:49:16] Error: invalid transactions: errors at tx 0: tx unable to pay base fee (block number=3704 hash=ee3a234b297c792ffbecc5f90042f053a14bb6760ec4058e61bca3f20d88c292)     at BlockHeader._error (/Volumes/Ethereum/ethereumjs-monorepo/packages/block/src/header.ts:857:15)
    at Block.validateData (/Volumes/Ethereum/ethereumjs-monorepo/packages/block/src/block.ts:272:25)
    at Block.validate (/Volumes/Ethereum/ethereumjs-monorepo/packages/block/src/block.ts:258:16)
    at /Volumes/Ethereum/ethereumjs-monorepo/packages/blockchain/src/index.ts:883:9
    at Blockchain.runWithLock (/Volumes/Ethereum/ethereumjs-monorepo/packages/blockchain/src/index.ts:410:21)
    at Blockchain._putBlockOrHeader (/Volumes/Ethereum/ethereumjs-monorepo/packages/blockchain/src/index.ts:854:5)
    at Blockchain.putBlock (/Volumes/Ethereum/ethereumjs-monorepo/packages/blockchain/src/index.ts:809:5)
    at Blockchain.putBlocks (/Volumes/Ethereum/ethereumjs-monorepo/packages/blockchain/src/index.ts:795:7)
    at Chain.putBlocks (/Volumes/Ethereum/ethereumjs-monorepo/packages/client/lib/blockchain/chain.ts:274:5)
    at BlockFetcher.store (/Volumes/Ethereum/ethereumjs-monorepo/packages/client/lib/sync/fetcher/blockfetcher.ts:84:5)

@jochem-brouwer
Copy link
Member Author

jochem-brouwer commented Apr 26, 2021

Another note; we only connect to Nethermind, other 3 bootnodes are up, have to figure out what is the cause of this. http://eip1559-testnet.ops.pegasys.tech:3001/

packages/block/src/block.ts Outdated Show resolved Hide resolved
@holgerd77
Copy link
Member

"Another node; we only connect to Nethermind"

You're too much in @jochem-brouwer. 😂 I've taken the freedom to correct. 😄

@@ -110,7 +110,7 @@ export class Chain extends EventEmitter {
db: options.chainDB,
common: this.config.chainCommon,
validateBlocks: true,
validateConsensus: false,
validateConsensus: true,
Copy link
Member

Choose a reason for hiding this comment

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

This is putting too much load on the PoW sync, I guess what we can do is just to activate for PoA by including a conditional switch along the common instance setting from above.

@holgerd77
Copy link
Member

@ryanio hmm, still not sure if #1222 is fixing the problem, I did a rebase here locally and removed 42d83d0 (so mainly the constant bootstrap retriggering, setting maxPerRequest to 1 is not relevant yet in this context here) - also did another npm run bootstrap locally from within this branch to make sure - and yet again the Send BlockHeaders message is not to be seen. 😕

Phew, tricky thing.

@ryanio
Copy link
Contributor

ryanio commented Apr 27, 2021

@holgerd77 this is tricky indeed, I rebased this branch on master (didn't touch the commit you specified) and was able to recreate the issue again.

I have a feeling it's still some kind of promise race condition we haven't handled properly. As a test I added a 5s timeout after starting the servers but before calling bootstrap (packages/client/lib/client.ts):

    ...
    await Promise.all(this.config.servers.map((s) => s.start()))

    // wait 5s
    function timeout(ms: number) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }
    await timeout(5000)

    await Promise.all(this.config.servers.map((s) => s.bootstrap()))
    ...

and that worked for me! I got a Send GET_BLOCK_HEADERS line...so I will keep tracing this async code and see if there is something we are missing or not being awaited properly. I just tried again with 1s and that even worked. I also tried with setImmediate with no timeout period but that didn't work.

We have the @typescript-eslint/no-floating-promises rule turned off in packages/devp2p/.eslintrc.js so I have a hunch that it may be some floating promise causing the problem.

@holgerd77 holgerd77 marked this pull request as ready for review May 19, 2021 10:34
@holgerd77
Copy link
Member

Guys, I will now merge this in here, tests are passing and I've given all code parts another final look. I have also written extensive tests for the tx library to lift the coverage up again to a decent level and have given all changes in the various libraries at least a rough and often somewhat thorough review.

We also do not have an imminently urgent release, at the same time more and more is worked "around" this one huge PR and all the other smaller work is blocked to a greater extend.

Everyone can still do reviews on parts where he feels the need, then please integrate your change requests along follow-up PRs.

Hope you can go along, but I have once again the feeling that we are at some point where things are not getting better by pushing this ahead. 😋 😀

Thanks @jochem-brouwer for this great work here! 🎉

Copy link
Member

@holgerd77 holgerd77 left a comment

Choose a reason for hiding this comment

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

LGTM

@holgerd77 holgerd77 merged commit a03be0f into master May 19, 2021
@holgerd77 holgerd77 deleted the eip1559 branch May 19, 2021 10:43
@holgerd77
Copy link
Member

Phew, 86 commits (and all very much decent ones, and not "fixed linting", "minor changes", "forgot to add x" 😛 ).

@@ -4,7 +4,10 @@ module.exports = {
plugin: 'typedoc-plugin-markdown',
readme: 'none',
gitRevision: 'master',
exclude: 'test/**/*.ts',
exclude: [
'src/util.ts',
Copy link
Member Author

Choose a reason for hiding this comment

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

Why do we exclude this?

Copy link
Member

Choose a reason for hiding this comment

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

The API of this feels too unfinished to me and I would like to keep this internal for now and give this some more thought and have some more discussions around it. I think no one every really reviewed these code parts (including me) and this would expose a huge new API surface.

Some things I would like to discuss (but which doesn't need to be discussed now, just for the mention):

  • Is this the best way to expose this functionality or might there be better - eventually more integrated - solutions (e.g. to re-bind the methods to the affected tx classes, just as some first idea)?
  • Relationship of this getAccessListData() (returning AccessListJSON as one of two items) and the getAccessListJSON() method
  • Should getDataFeeEIP2930() be exposed (I have the base feeling that methods which need a Common as an input often point to some suboptimality in design - we had these cases in the past - can't really point towards a concrete solution thought atm yet)?

I will actually open this as an issue, otherwise it will likely be too tempting to start the discussion here. 😄

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

Successfully merging this pull request may close these issues.

3 participants