-
Notifications
You must be signed in to change notification settings - Fork 324
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
[state] convert clean address to zero-nonce type #3991
Conversation
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.
as discussed, this feature could be deleted after hardfork if the accountType is updated from 0 to 1
c9bf2a9
to
bb20925
Compare
action/protocol/account/transfer.go
Outdated
@@ -66,6 +66,7 @@ func (p *Protocol) handleTransfer(ctx context.Context, tsf *action.Transfer, sm | |||
|
|||
if fCtx.FixGasAndNonceUpdate || tsf.Nonce() != 0 { | |||
// update sender Nonce | |||
sender.CheckConvertToZeroNonceType(tsf.Nonce()) |
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.
don't need a hard-fork flag here, b/c this would only happen after the hard-fork when the nonce of clean address is changed by AdjustNonceForCleanAddress()
to 0
for now, the first nonce of a clean address remains == 1, so this does no harm
just realized more changes are needed for |
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #3991 +/- ##
==========================================
+ Coverage 75.38% 76.18% +0.80%
==========================================
Files 303 337 +34
Lines 25923 28731 +2808
==========================================
+ Hits 19541 21888 +2347
- Misses 5360 5731 +371
- Partials 1022 1112 +90 ☔ View full report in Codecov by Sentry. |
api/coreservice.go
Outdated
return nonce, err | ||
} | ||
g := core.Genesis() | ||
if nonce > 1 || !g.IsSumatra(core.TipHeight()) { |
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.
why IsSumatra
? what's the difference from UseZeroNonceForFreshAccount
?
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.
IsSumatra()
is the same flag as UseZeroNonceForFreshAccount
, here we don't have a ctx
API service does not affect past blocks, so after the hard-fork, this check will be removed
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.
if so, be consistent with g.IsToBeEnabled(core.TipHeight())
@@ -344,6 +345,9 @@ func (stateDB *StateDBAdapter) GetNonce(evmAddr common.Address) uint64 { | |||
} | |||
pendingNonce-- | |||
} | |||
if pendingNonce == 1 && stateDB.convertFreshAddress { |
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 we remove pendingNonce == 1
? same question for all the other places making a similar check outside of function AdjustNonceForFreshAccount
state/account.go
Outdated
@@ -178,6 +187,16 @@ func (st *Account) PendingNonce() uint64 { | |||
} | |||
} | |||
|
|||
// AdjustNonceForFreshAccount adjust the nonce for a fresh legacy account | |||
func (st *Account) AdjustNonceForFreshAccount(nonce uint64) uint64 { |
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.
Better to be a util function, instead of a struct 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.
change the name to make it more correct
action/protocol/account/transfer.go
Outdated
@@ -66,6 +66,7 @@ func (p *Protocol) handleTransfer(ctx context.Context, tsf *action.Transfer, sm | |||
|
|||
if fCtx.FixGasAndNonceUpdate || tsf.Nonce() != 0 { | |||
// update sender Nonce | |||
sender.ConvertFreshAccountToZeroNonceType(tsf.Nonce()) |
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.
if acc.IsNewbieAccount() && acc.AccountType() == 0 && useZeroNonce {
acc.ConvertFreshAccountToZeroNonceType()
}
// Make sure the value matches if acc.PendingNonce() is called
Other places related to setpendingnonce/pendingnonce are similar
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.
acc.IsNewbieAccount() && acc.AccountType() == 0
is duplicate with what's checked inside ConvertFreshAccountToZeroNonceType
added the useZeroNonce
flag check
4d9fb01
to
fc7e6cb
Compare
api/coreservice.go
Outdated
return nonce, err | ||
} | ||
g := core.Genesis() | ||
if nonce > 1 || !g.IsSumatra(core.TipHeight()) { |
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.
if so, be consistent with g.IsToBeEnabled(core.TipHeight())
@@ -366,7 +370,11 @@ func (ws *workingSet) checkNonceContinuity(ctx context.Context, accountNonceMap | |||
return errors.Wrapf(err, "failed to get the confirmed nonce of address %s", srcAddr) | |||
} | |||
sort.Slice(receivedNonces, func(i, j int) bool { return receivedNonces[i] < receivedNonces[j] }) | |||
pendingNonce := confirmedState.PendingNonce() | |||
if useZeroNonce { | |||
pendingNonce = confirmedState.PendingNonceConsideringFreshAccount() |
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.
PendingNonceConsideringFreshAccount is conditional? The name indicates the judging is done inside the func
@@ -178,6 +187,16 @@ func (st *Account) PendingNonce() uint64 { | |||
} | |||
} | |||
|
|||
// PendingNonceConsideringFreshAccount return the pending nonce considering fresh legacy account | |||
func (st *Account) PendingNonceConsideringFreshAccount() uint64 { |
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.
How about naming it PendingNonce()
and renaming the original LegacyPendingNonce()
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.
SetPendingNonce()
should also be updated for this change
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.
PendingNonce
has too many uses in the code
if we want to do this, can do in a separate PR
@@ -175,3 +175,45 @@ func TestClone(t *testing.T) { | |||
require.Equal(big.NewInt(200), ss.Balance) | |||
require.Equal(big.NewInt(200+100), account.Balance) | |||
} | |||
|
|||
func TestConvertFreshAddress(t *testing.T) { |
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.
e2etest is also required to check working well in evm
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.
added in latest commit
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.
added in latest commit
16fb160
to
2d763e0
Compare
e2etest/local_transfer_test.go
Outdated
make([]byte, 4), | ||
uint64(200000), big.NewInt(1), | ||
TsfSuccess, "", | ||
"Transfer with nonce 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.
Why behavior changes when this feature not enabled
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 test is "transfer with nonce 0". Before enable this, legacy account first tx has nonce=1
, so the test will fail. Now with this feature enabled, the first tx can have nonce=0
so the test can pass
} { | ||
a, err := accountutil.AccountState(ctx, sf, v.a) | ||
require.NoError(err) | ||
require.EqualValues(1, a.AccountType()) |
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.
add case to check if first tx nonce==1
action/protocol/account/transfer.go
Outdated
@@ -66,6 +66,9 @@ func (p *Protocol) handleTransfer(ctx context.Context, tsf *action.Transfer, sm | |||
|
|||
if fCtx.FixGasAndNonceUpdate || tsf.Nonce() != 0 { | |||
// update sender Nonce | |||
if fCtx.UseZeroNonceForFreshAccount { | |||
sender.ConvertFreshAccountToZeroNonceType(tsf.Nonce()) |
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 can do before protocol.Handle
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.
see latest commit
return nil, errors.Wrapf(err, "failed to store converted sender %s", actCtx.Caller.String()) | ||
} | ||
} | ||
} |
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.
do the check/conversion before action.Handle()
action/protocol/account/transfer.go
Outdated
@@ -66,9 +66,6 @@ func (p *Protocol) handleTransfer(ctx context.Context, tsf *action.Transfer, sm | |||
|
|||
if fCtx.FixGasAndNonceUpdate || tsf.Nonce() != 0 { | |||
// update sender Nonce | |||
if fCtx.UseZeroNonceForFreshAccount { | |||
sender.ConvertFreshAccountToZeroNonceType(tsf.Nonce()) | |||
} |
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.
revert change in 1st commit
action/protocol/execution/evm/evm.go
Outdated
@@ -405,9 +405,6 @@ func prepareStateDB(ctx context.Context, sm protocol.StateManager) (*StateDBAdap | |||
if !featureCtx.CorrectGasRefund { | |||
opts = append(opts, ManualCorrectGasRefundOption()) | |||
} | |||
if featureCtx.UseZeroNonceForFreshAccount { | |||
opts = append(opts, ConvertFreshAddressOption()) | |||
} |
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.
revert change in 1st commit
@@ -373,9 +358,6 @@ func (stateDB *StateDBAdapter) SetNonce(evmAddr common.Address, nonce uint64) { | |||
log.L().Debug("Called SetNonce.", | |||
zap.String("address", addr.String()), | |||
zap.Uint64("nonce", nonce)) | |||
if stateDB.convertFreshAddress { | |||
s.ConvertFreshAccountToZeroNonceType(nonce) | |||
} |
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.
revert change in 1st commit
accountCreationOpts = append(accountCreationOpts, state.LegacyNonceAccountTypeOption()) | ||
} | ||
acc, err := accountutil.LoadOrCreateAccount(sm, addr, accountCreationOpts...) | ||
if err != nil { | ||
return err | ||
} | ||
if !skipSetNonce { | ||
if fCtx.UseZeroNonceForFreshAccount { | ||
acc.ConvertFreshAccountToZeroNonceType(nonce) | ||
} |
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.
revert change in 1st commit
action/protocol/staking/protocol.go
Outdated
accountCreationOpts = append(accountCreationOpts, state.LegacyNonceAccountTypeOption()) | ||
} | ||
acc, err := accountutil.LoadAccount(sm, actionCtx.Caller, accountCreationOpts...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if fCtx.UseZeroNonceForFreshAccount { | ||
acc.ConvertFreshAccountToZeroNonceType(actionCtx.Nonce) | ||
} |
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.
revert change in 1st commit
actpool/actqueue.go
Outdated
balance = new(big.Int).Set(confirmedState.Balance) | ||
acts = make([]action.SealedEnvelope, 0, len(q.items)) | ||
) | ||
q.mu.RLock() | ||
defer q.mu.RUnlock() | ||
if confirmedState.IsLegacyFreshAccount() && nonce == 0 { | ||
// for a legacy fresh account, the nonce of first tx could be either 0 or 1 |
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 nonce of 1st tx is undeterministic
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.
updated in latest commit
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.
let's further simplify the logic to: "the nonce of the first action for a fresh account with legacy type could only be 0 after hard fork no matter how". The only problem for the simplified logic is that a fresh account with legacy type may send an action of nonce 1 may need to resend an action of nonce 0, which is not a big problem.
state/account.go
Outdated
@@ -166,6 +171,15 @@ func (st *Account) SetPendingNonce(nonce uint64) error { | |||
return nil | |||
} | |||
|
|||
// ConvertFreshAccountToZeroNonceType converts a fresh legacy account to zero-nonce account | |||
func (st *Account) ConvertFreshAccountToZeroNonceType(nonce uint64) { |
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.
delete parameter nonce
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 to make sure the conversion only happens for a tx with nonce = 0
yes updated this in latest commit |
api/coreservice.go
Outdated
return nonce, err | ||
} | ||
g := core.Genesis() | ||
if nonce > 1 || !g.IsToBeEnabled(core.TipHeight()) { |
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.
nonce returned in line 494 is from ap
. if nonce == 1 && after hard fork
, shall we return 1?
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.
fixed in latest commit
@@ -166,6 +171,17 @@ func (st *Account) SetPendingNonce(nonce uint64) error { | |||
return nil | |||
} | |||
|
|||
// ConvertFreshAccountToZeroNonceType converts a fresh legacy account to zero-nonce account | |||
func (st *Account) ConvertFreshAccountToZeroNonceType(nonce uint64) bool { |
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 this conversion be moved to SetPendingNonce as:
switch st.accountType {
case 1: ...
case 0:
if st.accountType == 0 && st.nonce == 0 && nonce == 1 {
st.accountType = 1
} else {
....
}
default:
...
}
st.nonce++
The hard fork feature and nonce has been checked in checkNonceContinuity
, thus we can delete this function as well as the place calling it
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.
it's very hard to do insideSetPendingNonce
alone, because EVM use emvstateadaptor's GetNonce
and SetNonce
to access the nonce value.
In order to achieve nonce == 1
in the example you gave, we'll need add code inside GetNonce
and SetNonce
-- which is basically the code moved to workingset.go
in commit c03396e
I prefer changes around |
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.
Three places could be changed to achieve the conversion:
- When returning a confirmed state of an account, passing the hard fork symbol
- Modify account.PendingNonce returns the right pending nonce
- SetPendingNonce sets the right pending nonce and modify the account type accordingly
This PR tries to resolve the problem by modifying the process but not the object containing the feature. We need a followup PR to do it in an OO way.
Quality Gate passedThe SonarCloud Quality Gate passed, but some issues were introduced. 1 New issue |
Description
If a legacy account has never initiated an outgoing tx, we convert it to a zero-nonce type account. This enables us to do deterministic deployment
Fixes #(issue)
Type of change
Please delete options that are not relevant.
How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
Test Configuration:
Checklist: