-
Notifications
You must be signed in to change notification settings - Fork 90
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
eth2util/deposit: refactor deposit data and add tests #521
Conversation
Codecov Report
@@ Coverage Diff @@
## main #521 +/- ##
==========================================
+ Coverage 54.77% 54.82% +0.05%
==========================================
Files 91 92 +1
Lines 8480 8574 +94
==========================================
+ Hits 4645 4701 +56
- Misses 3226 3248 +22
- Partials 609 625 +16
Continue to review full report at Codecov.
|
93dd5b6
to
5175627
Compare
@@ -0,0 +1,34 @@ | |||
{ |
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.
store the privatekey as in the test code directly:
const privkey = "acb123adc4212367"
eth2util/keystore/keystore.go
Outdated
// keystore json file representation as a Go struct. | ||
type keystore struct { | ||
// Keystore json file representation as a Go struct. | ||
type Keystore struct { |
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.
Best not refactor other packages just for testing.
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 is better code and it is already done and very short. In general I agree of not getting into other stuff outside the PR goal
"testing" | ||
) | ||
|
||
func TestDepositData1Serialization(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.
As single test should be enough:
root, err := deposit.MessageRoot(...)
sig := testSign(root)
resp, err := deposit.MarshalDepositData(..., sig)
testutil.RequireGoldenBytes(t, resp)
@xenowits I don't undestand why there is a feature flag called eth2util? is it eth2util a feature? the name does not suggest a feature |
Please rebase this on latest main 🙏 |
.pre-commit-config.yaml
Outdated
@@ -1,7 +1,7 @@ | |||
repos: | |||
# First run code formatters | |||
- repo: https://github.com/pre-commit/pre-commit-hooks | |||
rev: v4.1.0 | |||
rev: v4.2.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.
please move this a separate PR.
6cce1c8
to
a16e2c3
Compare
I removed the feature_flag as it was not necessary. |
eth2util/deposit/deposit_data.go
Outdated
) | ||
|
||
// GetMessageRoot returns both the hash root and the signing root of the deposit message. | ||
func GetMessageRoot(pubkey eth2p0.BLSPubKey, withdrawalCreds [32]byte, forkVersion eth2p0.Version) (eth2p0.Root, eth2p0.Root, error) { |
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.
when returning identical types, it is best to use named parameters so it is clear which one is which.
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.
Wouldn't a withdrawalAddr string
be a more convenient format for users of this package?
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.
| when returning identical types, it is best to use named parameters so it is clear which one is which.
very good!! let's make code self documenting, we should name return values unless they are super 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.
changed this to return only the hash root
eth2util/deposit/deposit_data.go
Outdated
idx := hh.Index() | ||
// NewDepositData returns the json serialized DepositData. | ||
func NewDepositData(pubkey eth2p0.BLSPubKey, withdrawalAddr string, sig eth2p0.BLSSignature, network string) ([]byte, error) { | ||
forkVersion := NetworkToForkVersion(network) |
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 unexport all functions and types, except MarshalDepositData
and GetMessageRoot
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.
rename NewDepositData
to MarshalDepositData
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, I agree New
should be reserved for constructors.
let's as you say unexport as default, and export only things that we need outside
eth2util/deposit/deposit_data.go
Outdated
// DepositMessageRoot is the hash tree root of DepositMessage. | ||
DepositMessageRoot eth2p0.Root | ||
// DOMAIN_DEPOSIT. See spec: https://benjaminion.xyz/eth2-annotated-spec/phase0/beacon-chain/#domain-types | ||
depositDomainType = []byte{0x03, 0x00, 0x00, 0x00} |
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.
wrap in proper type = eth2p0.DomainType([4]byte{0x03, 0x00, 0x00, 0x00})
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.
same for zeroBytes32
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.
there isn't a proper type for zeroBytes32
eth2util/deposit/deposit_data.go
Outdated
} | ||
root, err := forkData.HashTreeRoot() | ||
if err != nil { | ||
return eth2p0.Domain{}, errors.Wrap(err, "failed to calculate signature domain") |
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.
nit: can be more concise with error messages: hash fork data
) | ||
|
||
func TestDepositData(t *testing.T) { | ||
depositData, err := DepositDataFromFile(t, depositDataFile) |
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 not think you need to ever read deposit data from file, just calculate the expected value and do golden file comparison.
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.
done!
eth2util/deposit/deposit_data.go
Outdated
case "mainnet": | ||
fvBytes = []byte{0x00, 0x00, 0x00, 0x00} | ||
case "prater": | ||
fvBytes = []byte{0x00, 0x00, 0x10, 0x20} |
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.
can return proper types directly: return eth2p0.Version([4]byte{0x00, 0x00, 0x10, 0x20}
eth2util/deposit/deposit_data.go
Outdated
func (d depositData) HashTreeRoot() ([32]byte, error) { | ||
b, err := ssz.HashWithDefaultHasher(d) | ||
// GetDataRoot returns both the hash root and the signing root of the deposit data. | ||
func GetDataRoot(pubkey eth2p0.BLSPubKey, withdrawalCreds [32]byte, sig eth2p0.BLSSignature, forkVersion eth2p0.Version) (eth2p0.Root, eth2p0.Root, error) { |
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.
only one of the two responses is ever used, so suggest only retuning that one thing
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 corrected that
@@ -13,6 +13,7 @@ | |||
// You should have received a copy of the GNU General Public License along with | |||
// this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
|||
// Package deposit provides functions to create deposit data files. |
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.
package level godoc is important
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.
noted!
// zeroes11 refers to a zeroed out 11 byte array. | ||
zeroBytes11 = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} | ||
|
||
// zeroes refers to a zeroed out 32 byte array. | ||
zeroBytes32 = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} |
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.
zero types not required
// getMessageRoot returns a deposit message hash root created by the parameters. | ||
func getMessageRoot(pubkey eth2p0.BLSPubKey, withdrawalAddr string) (eth2p0.Root, error) { |
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.
made it private
creds, err := withdrawalCredsFromAddr(withdrawalAddr) | ||
if err != nil { | ||
return eth2p0.Root{}, errors.Wrap(err, "withdrawal credentials") |
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.
only wrap external packages, no need to wrap Charon packages or Charon functions (since the errors have proper stack traces)
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.
noted!
@@ -66,101 +60,87 @@ func GetMessageRoot(pubkey eth2p0.BLSPubKey, withdrawalAddr string) (eth2p0.Root | |||
return hashRoot, nil | |||
} | |||
|
|||
// GetDataRoot returns the hash root of the deposit data. | |||
func GetDataRoot(pubkey eth2p0.BLSPubKey, withdrawalAddr string, sig eth2p0.BLSSignature) (eth2p0.Root, error) { |
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 function doesn't do much, so I just inlined it
func GetSigningRoot(forkVersion eth2p0.Version, root eth2p0.Root) ([32]byte, error) { | ||
domain, err := GetDomain(forkVersion, depositDomainType) | ||
// GetMessageSigningRoot returns the deposit message signing root created by the provided parameters. | ||
func GetMessageSigningRoot(pubkey eth2p0.BLSPubKey, withdrawalAddr string, network string) ([32]byte, error) { |
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 the new "Step1" function of this package
var creds [32]byte | ||
copy(creds[0:], eth1AddressWithdrawalPrefix) // Add 1 byte prefix. | ||
copy(creds[12:], addrBytes) // Add 20 bytes of ethereum address suffix. |
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.
more succinct to work directly with array, then zero11 also not required.
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, since the default zero value of a byte is 0
@@ -207,6 +174,8 @@ func networkToForkVersion(network string) eth2p0.Version { | |||
return [4]byte{0x70, 0x00, 0x00, 0x69} | |||
case "gnosis": | |||
return [4]byte{0x00, 0x00, 0x00, 0x64} | |||
case "mainnet": // Default to mainnet | |||
fallthrough | |||
default: | |||
return [4]byte{0x00, 0x00, 0x00, 0x00} |
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 isn't obviously that this is mainnet
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.
oh i get, this is the first usecase i have seen where fallthrough
makes sense. thanks for pointing this!
msgRoot, err := deposit.GetMessageRoot(pubkey, withdrawalAddr) | ||
require.NoError(t, err) | ||
|
||
forkVersion := eth2p0.Version([4]byte{0x00, 0x00, 0x10, 0x20}) | ||
msgSigningRoot, err := deposit.GetSigningRoot(forkVersion, msgRoot) |
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.
now this is just a single step. Also aligned use of network between both functions. Also aligned function signatures
require.NoError(t, err) | ||
|
||
testutil.RequireGoldenBytes(t, serializedDepositData) |
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.
golden files allow updating, this is not applicable in this usecase
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.
got it. So, for test data files like this which are static, golden files are not required👍
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.
yeah, golden files are generated, in this case the test file is a static external test file
deposit data
to use types frometh2p0
(ex).category: refactor
ticket: #481