-
Notifications
You must be signed in to change notification settings - Fork 782
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
Add DAO support #843
Add DAO support #843
Conversation
Codecov Report
Flags with carried forward coverage won't be shown. Click here to find out more. |
This pull request fixes 1 alert when merging 5960ee2 into ea73164 - view on LGTM.com fixed alerts:
|
00fca2d
to
91194aa
Compare
This pull request fixes 1 alert when merging 91194aa into ea73164 - view on LGTM.com fixed alerts:
|
91194aa
to
4498862
Compare
This pull request fixes 1 alert when merging 4498862 into ea73164 - view on LGTM.com fixed alerts:
|
Hi @jochem-brouwer, great that you gave this such a quick start! 😄 👍 There is no need for both of these You can get the activation block (the HF block, or am I missing something?) by using the Common.hardforkBlock() function, you can also explicitly provide the HF there if you want the The integration status (is this HF applied on the respective chain) is directly integrated into the Yeah, for these accounts I would also suggest a separate config file, maybe really do an additional |
@jochem-brouwer looking good! I'd agree with @holgerd77 that we can set up a file at Maybe |
This pull request introduces 1 alert when merging 5c15e07 into d08ba7c - view on LGTM.com new alerts:
|
This pull request introduces 1 alert when merging a847ba6 into d08ba7c - view on LGTM.com new alerts:
|
45eaf37
to
ccca2fb
Compare
re-lint everything [VM] fix commented out errors [VM] fix test [VM] really fix test
[Common] fix DAO activation block kovan/goerli [Block] remove unused BN [Common/VM] fix tests
ccca2fb
to
ecb7bdf
Compare
Allright this seems to be fixed and I really like it now as it is much cleaner. Thanks for the suggestions @holgerd77 @ryanio 😄 ! For some reason I was not aware of this Common functionality. Please explicitly check the edited Goerli test, I think it makes a lot of sense to set the DAO blocks to |
@@ -26,7 +26,7 @@ | |||
}, | |||
{ | |||
"name": "dao", | |||
"block": 0, | |||
"block": null, | |||
"forkHash": "0xa3f5ab08" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I do get this right that DAO support is not active neither on Goerli nor on Kovan, correct?
Then this change makes a lot of sense and is technically also a bug fix along the way. Wonder if we should generally remove all the null
DAO
entries from Common
completely since these are just HFs not being present on the respective chains (and never will be).
For null
I always had the semantics "HF didn't happen yet but has some settings and will happen some time in the future" in mind, so e.g. the state of the Berlin
HF right now. Technically it shouldn't make any difference though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do get the confusion here. But just for comparision:
geth
: config="{ChainID: 1 Homestead: 1150000 DAO: 1920000 DAOSupport: true (...)
geth --goerli
: config="{ChainID: 5 Homestead: 0 DAO: <nil> DAOSupport: true (...)
I just checked all 4 testnets and neither of them has any contract/code at "bf4ed7b27f1d666546e30d74d50d173d20bca754" (the DAO withdraw contract on mainnet)
This is thus also reflected in all 4 testnet common files now (they all have the DAO block set to null
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @jochem-brouwer, super cool that you picked this up so quickly 😀 , some comments to address.
packages/common/tests/hardforks.ts
Outdated
@@ -136,8 +136,8 @@ tape('[Common]: Hardfork logic', function (t: tape.Test) { | |||
st.equal(c.activeHardforks().length, 8, msg) | |||
|
|||
c = new Common('goerli') | |||
msg = 'should return 9 active HFs for goerli' | |||
st.equal(c.activeHardforks().length, 9, msg) | |||
msg = 'should return 8 active HFs for goerli' // `geth --goerli` gives `DAOSupport: true` but `DAO: <nil>` (i.e. do not apply DAO state transition at any block) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this comment is rather confusing than helpful for future generations 🙂, I would tend to remove it.
packages/block/src/header.ts
Outdated
// verify the extraData field. | ||
const blockNumber = new BN(this.number) | ||
const DAOActivationBlock = new BN(this._common.hardforkBlock('dao')) | ||
if (blockNumber.gte(new BN(DAOActivationBlock))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DAOActivationBlock
is double-wrapped here in a BN
.
I would generally tend to completely leave DAOActivationBlock
as a number
and use the *n
functionality from BN.js
, there is no chance that a DAOActivationBlock
will exceed the allowed JavaScript integer range (I was actually wondering here along why we use BN
instances for block number calculation at all, e.g. in calculateOmmerReward, but I dimly remember that there might be some reason for it, something like some End-User-Tool (Truffle?) running the VM on very high block numbers in some circumstances)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(always a problem if something like this is not documented 😕 , then on the next occasion someone else is removing stuff like that again because reasoning is not very obvious)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding why we are using BNs in block numbers: I think there might be some ethereum/tests case where it could use a big number? The test cases test some pretty extreme things (which is OK of course if they are valid within the protocol).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will keep it a BN; this allows for flexibility in case someone wants to ever use a gigantic block number for the DAO transition.
packages/block/src/header.ts
Outdated
@@ -13,6 +13,9 @@ import { Blockchain, BlockHeaderData, BufferLike, ChainOptions, PrefixedHexStrin | |||
import { Buffer } from 'buffer' | |||
import { Block } from './block' | |||
|
|||
const DAO_ExtraData = Buffer.from('64616f2d686172642d666f726b', 'hex') | |||
const DAO_ForceExtraDataRange = 10 // force extra data be DAO_ExtraData for X blocks after DAO activation block |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this ExtraData
thing actually coming from? I don't find this in EIP-779? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(eventually you can directly add this to the comment, maybe no URL if not a very trusted/simple one, but rather an EIP number or so if there is one)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I got this from both geth
(see here) and from ethereum/tests
(all DAO tests (which are only 4...) check explicitly that the extra data field is set to this, see this for instance this test comment). I don't know why it is not in the EIP. Actually I should open a PR for the EIP in order to fix this.
await this.stateManager.putAccount(DAORefundContractAddress, DAORefundAccount) | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is such specialized code not very relevant in the very most reads of the source file I would tend to put this into a separate function _applyDAOHardfork()
and extract from runBlock()
, maybe after the two if
checks (so "if active & block correct", maybe these can be generally combined into one &&
-concatenated check to avoid the deeper indentation level).
} | ||
common = Common.forCustomChain('mainnet', { | ||
hardforks: editedForks | ||
}, 'homestead') // we should be on the "homestead" fork |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would love if we can avoid this code block since this is such a long code part for such a super-specialized one case application. Any idea anyone?
If we don't find an optimization I would also here tend to move the functionality (create the custom common instance, so all code within the first if
clause switch) to a separate function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could add functionality to Common
where we can specify the activation blocks of each fork? Is the Common
supposed to be static after you instantiate it? Then we could just add a function where we setHardforkBlock
.
packages/vm/tests/api/runBlock.js
Outdated
} | ||
let common = Common.forCustomChain('mainnet', { | ||
hardforks: editedForks | ||
}, 'homestead') // we should be on the "homestead" fork |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, just seeing that this code is repeated here again. Can you then put it into tests/util.js
as its own function? Then I think it is also viable to leave "as is".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes this is a good solution.
let DAORefundAccount = await suite.vm.stateManager.getAccount(DAORefundAddress) | ||
t.true(DAORefundAccount.balance.equals(Buffer.from('7777', 'hex'))) // verify that the refund account gets the summed balance of the original refund account + two child DAO accounts | ||
|
||
t.end() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice tests, really cool that you went this extra path! 😀 Small typo in both of the // verify our funded account is now has 0 balance
comments (remove the is
).
packages/vm/tests/tester.js
Outdated
|
||
let FORK_CONFIG_VM | ||
if (FORK_CONFIG.toLowerCase() == "dao") { | ||
FORK_CONFIG_VM = "homestead" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is correct? If so, can you add a comment here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a second look: this is just for the blockchain tests, right? Can we then move this over there and leave the simple logic here untouched? I think this is better understandable then in this context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should add a DAO fork to hardforks support of VM, don't know why I did this actually 😅
[Block] fix extra data range
299bdb7
to
c035e03
Compare
Tests should pass. Please re-review @holgerd77 😄 |
@evertonfraga what is actually this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This look good 👍 , thanks @jochem-brouwer, will add one commit (see comments) and then merge.
packages/block/src/header.ts
Outdated
@@ -13,6 +13,9 @@ import { Blockchain, BlockHeaderData, BufferLike, ChainOptions, PrefixedHexStrin | |||
import { Buffer } from 'buffer' | |||
import { Block } from './block' | |||
|
|||
const DAO_ExtraData = Buffer.from('64616f2d686172642d666f726b', 'hex') | |||
const DAO_ForceExtraDataRange = 9 // force extra data be DAO_ExtraData for X blocks after DAO activation block (see: https://blog.slock.it/hard-fork-specification-24b889e70703) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, thanks for the reference here!
packages/block/src/header.ts
Outdated
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry that this didn't occur to me before, a bit analogue to other requests since all this DAO code is so special: can we extract this code block to a separate _checkDAOForkExtraData()
(or similar) method since this code block is unproportionally to its importance bloating the constructor code so much right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(with function placement optimally also very much at the end of the file along the other _*
functions)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update: I will just add this myself along the review and then approve to streamline the process. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you also update the Changelog? 😄
let account = await state.getAccount(Buffer.from(address, 'hex')) | ||
DAOBalance.iadd(new BN(account.balance)) | ||
// clear the accounts' balance | ||
account.balance = Buffer.alloc(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will likely never learn these kind of things 🤨 - they just seem to not fit in my head - but is it clear here that setting the account balance to zero is done with the empty Buffer ([Buffer ]
) and not the zero Buffer ([Buffer 00])
)?
Will not make it a blocker though since transition test runs from ethereum/tests
seem to indicate that this is correct and leads to the correct transition state roots.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is worth checking out at some point if we would handle it correctly if we put a 1-byte zero-byte (😅 ). However to calculate the state root the actual Buffer should be empty and not Buffer.from('00','hex') (1 byte length) otherwise state root calculation gets messed up.
@@ -16,12 +16,12 @@ | |||
"coverage:test": "tape './tests/api/**/*.js' ./tests/tester.js --state --dist", | |||
"docs:build": "typedoc --options typedoc.js", | |||
"test:state": "ts-node ./tests/tester --state", | |||
"test:state:allForks": "echo 'Homestead TangerineWhistle SpuriousDragon Byzantium Constantinople Petersburg Istanbul MuirGlacier' | xargs -n1 | xargs -I v1 npm run test:state -- --fork=v1", | |||
"test:state:allForks": "echo 'Chainstart Homestead dao TangerineWhistle SpuriousDragon Byzantium Constantinople Petersburg Istanbul MuirGlacier' | xargs -n1 | xargs -I v1 npm run test:state -- --fork=v1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The convention here for the HF names is normally to apply camel case, so at least start with a capital letter (Dao
) (so but for dao it is a bit unclear to admit, could also be DAO
). We shouldn't deviate on such things too much since these kind of things always have the potential to lead to some not-wanted side effects at some point.
Won't make this a review blocker though.
@@ -24,11 +26,11 @@ module.exports = async function runBlockchainTest(options, testData, t) { | |||
validate = true | |||
} | |||
|
|||
const hardfork = options.forkConfigVM | |||
|
|||
const common = (options.forkConfigTestSuite == "HomesteadToDaoAt5") ? getDAOCommon(5) : new Common('mainnet', options.forkConfigVM) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, nice. 😄
const DAOCommon = Common.forCustomChain('mainnet', { | ||
hardforks: editedForks | ||
}, 'dao') | ||
return DAOCommon |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No blocker either, but just for awareness if this gets necessary on future work: this can be generalized to a getCommonWithCustomHFBlock()
function by also passing in the HF name. Then this can be used potentially for other use cases or HF transitions as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be addressed in #849 😄
…two DAO HF extra data block creation tests
Thanks for these changers, @holgerd77 😄 Only thing left to do before merging is updating the Changelog + ReadMe! Could you do that? |
@@ -85,7 +85,7 @@ jobs: | |||
# This is the most fair division among 1 directory vs. everything else | |||
args: ['--excludeDir=stTimeConsuming', '--dir=GeneralStateTests/stTimeConsuming'] | |||
# Run specific fork tests | |||
fork: ['MuirGlacier', 'Istanbul', 'Homestead', 'Chainstart'] | |||
fork: ['MuirGlacier', 'Istanbul', 'Homestead', 'Chainstart', 'dao'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does Chaintstart
refer to Frontier ("the genesis") here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @jochem-brouwer, went along and don't want to trigger a new CI run just for a one-line text addition. Let's do these CHANGELOG updates along some dedicated PRs until we caught up and can just add and switch to our new mode.
Will merge this in here for now.
This PR adds DAO support.
For some reason ethereum/tests does not test if the DAO actually gets completed (!?) soI added a test for this in the API test suite. (Note: DAO tests are actually tested in ethereum/tests, but our test runner currently does not verify this: see #842 )I don't like the location of this gigantic DAO account list, maybe we just want a seperate config-like file where we add these accounts.
I was a bit unsure if we should create a new Common for DAO but this seems to be like the better option to add some more flags to VM/Block/Blockchain in order to support it. (There is an explicit requirement here that we should specify which block the fork gets activated. We do not have this support in general for Common or the VM so this is a bit of unexplored territory).