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

eth2util/deposit: refactor deposit data and add tests #521

Merged
merged 4 commits into from
May 16, 2022

Conversation

xenowits
Copy link
Contributor

@xenowits xenowits commented May 13, 2022

  • refactor deposit data to use types from eth2p0 (ex).
  • Test generated deposit data against a sample output generated using eth2 cli.

category: refactor
ticket: #481

@xenowits xenowits marked this pull request as draft May 13, 2022 06:50
@codecov
Copy link

codecov bot commented May 13, 2022

Codecov Report

Merging #521 (34ab1c5) into main (7254daa) will increase coverage by 0.05%.
The diff coverage is 56.60%.

@@            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     
Impacted Files Coverage Δ
eth2util/deposit/deposit.go 56.60% <56.60%> (ø)
app/app.go 63.31% <0.00%> (-0.89%) ⬇️
core/qbft/qbft.go 84.90% <0.00%> (-0.81%) ⬇️
testutil/genchangelog/main.go 15.38% <0.00%> (+0.88%) ⬆️

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 7254daa...34ab1c5. Read the comment docs.

@xenowits xenowits force-pushed the xenowits/refactor-deposit-data branch from 93dd5b6 to 5175627 Compare May 13, 2022 07:02
@@ -0,0 +1,34 @@
{
Copy link
Contributor

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"

// keystore json file representation as a Go struct.
type keystore struct {
// Keystore json file representation as a Go struct.
type Keystore struct {
Copy link
Contributor

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.

Copy link
Contributor

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) {
Copy link
Contributor

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)

@leolara
Copy link
Contributor

leolara commented May 13, 2022

@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

@corverroos
Copy link
Contributor

Please rebase this on latest main 🙏

@@ -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
Copy link
Contributor

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.

@xenowits xenowits force-pushed the xenowits/refactor-deposit-data branch from 6cce1c8 to a16e2c3 Compare May 13, 2022 15:23
@xenowits xenowits marked this pull request as ready for review May 13, 2022 15:43
@xenowits
Copy link
Contributor Author

@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

I removed the feature_flag as it was not necessary.

)

// 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) {
Copy link
Contributor

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.

Copy link
Contributor

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?

Copy link
Contributor

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

Copy link
Contributor Author

@xenowits xenowits May 13, 2022

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

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)
Copy link
Contributor

@corverroos corverroos May 13, 2022

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

Copy link
Contributor

Choose a reason for hiding this comment

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

rename NewDepositData to MarshalDepositData

Copy link
Contributor

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

// 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}
Copy link
Contributor

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})

Copy link
Contributor

Choose a reason for hiding this comment

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

same for zeroBytes32

Copy link
Contributor Author

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

}
root, err := forkData.HashTreeRoot()
if err != nil {
return eth2p0.Domain{}, errors.Wrap(err, "failed to calculate signature domain")
Copy link
Contributor

@corverroos corverroos May 13, 2022

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)
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

case "mainnet":
fvBytes = []byte{0x00, 0x00, 0x00, 0x00}
case "prater":
fvBytes = []byte{0x00, 0x00, 0x10, 0x20}
Copy link
Contributor

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}

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) {
Copy link
Contributor

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes corrected that

@xenowits xenowits linked an issue May 13, 2022 that may be closed by this pull request
@@ -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.
Copy link
Contributor

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

noted!

Comment on lines 38 to 42
// 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}
Copy link
Contributor

Choose a reason for hiding this comment

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

zero types not required

Comment on lines +43 to +44
// getMessageRoot returns a deposit message hash root created by the parameters.
func getMessageRoot(pubkey eth2p0.BLSPubKey, withdrawalAddr string) (eth2p0.Root, error) {
Copy link
Contributor

@corverroos corverroos May 14, 2022

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")
Copy link
Contributor

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)

Copy link
Contributor Author

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) {
Copy link
Contributor

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) {
Copy link
Contributor

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

Comment on lines +158 to +160
var creds [32]byte
copy(creds[0:], eth1AddressWithdrawalPrefix) // Add 1 byte prefix.
copy(creds[12:], addrBytes) // Add 20 bytes of ethereum address suffix.
Copy link
Contributor

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.

Copy link
Contributor Author

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}
Copy link
Contributor

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

Copy link
Contributor Author

@xenowits xenowits May 14, 2022

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!

Comment on lines 50 to 54
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)
Copy link
Contributor

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)
Copy link
Contributor

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

Copy link
Contributor Author

@xenowits xenowits May 14, 2022

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👍

Copy link
Contributor

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

@xenowits xenowits added the merge when ready Indicates bulldozer bot may merge when all checks pass label May 16, 2022
@obol-bulldozer obol-bulldozer bot merged commit c9f8779 into main May 16, 2022
@obol-bulldozer obol-bulldozer bot deleted the xenowits/refactor-deposit-data branch May 16, 2022 04:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge when ready Indicates bulldozer bot may merge when all checks pass
Projects
None yet
Development

Successfully merging this pull request may close these issues.

dkg: generate deposit_data
3 participants