Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,8 @@ ci-release:
-w /go/src/$(PACKAGE_NAME) \
ghcr.io/goreleaser/goreleaser-cross:v1.21.12 \
release --clean --auto-snapshot

.PHONY: pregenerate-bls-keys
pregenerate-bls-keys: ## Pregenerate BLS keys for testing
go run ./tools/pregenerate_bls_keys/main.go > utils/keys/fixtures/bls_keys.json
@echo "BLS keys pregenerated in ./test_data/bls_keys.json"
73 changes: 18 additions & 55 deletions playground/artifacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"maps"
"math/big"
"os"
"path"
"path/filepath"
"reflect"
"strconv"
Expand All @@ -24,17 +23,16 @@ import (
"time"

"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/crypto/bls/common"
"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/OffchainLabs/prysm/v6/runtime/interop"
"github.com/OffchainLabs/prysm/v6/runtime/version"
gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
ecrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/flashbots/builder-playground/utils"
"github.com/hashicorp/go-uuid"
"github.com/flashbots/builder-playground/utils/keys"
"github.com/otiai10/copy"
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
"gopkg.in/yaml.v2"
)

Expand Down Expand Up @@ -188,11 +186,20 @@ func (b *ArtifactsBuilder) Build(out *output) error {
}

log.Println("Generating keys...")
priv, pub, err := interop.DeterministicallyGenerateKeys(0, 100)
keys, err := keys.GetPregeneratedBLSKeys()
if err != nil {
return err
}

var (
priv []bls.SecretKey
pub []bls.PublicKey
)
for _, key := range keys {
priv = append(priv, key.Priv)
pub = append(pub, key.Pub)
}

depositData, roots, err := interop.DepositDataFromKeysWithExecCreds(priv, pub, 100)
if err != nil {
return err
Expand All @@ -216,10 +223,7 @@ func (b *ArtifactsBuilder) Build(out *output) error {
"testnet/deploy_block.txt": "0",
"testnet/deposit_contract_block.txt": "0",
"testnet/genesis_validators_root.txt": hex.EncodeToString(state.GenesisValidatorsRoot()),
"data_validator/": &lighthouseKeystore{
privKeys: priv,
cacheDir: path.Join(out.homeDir, "cache", "data_validator"),
},
"data_validator/": &lighthouseKeystore{privKeys: keys},
})
if err != nil {
return err
Expand Down Expand Up @@ -562,64 +566,23 @@ func (o *output) WriteFile(dst string, data interface{}) error {
return nil
}

var secret = "secret"

type lighthouseKeystore struct {
privKeys []common.SecretKey
cacheDir string
}

func isExistingDir(path string) bool {
info, err := os.Stat(path)
if err == nil {
return info.IsDir()
}
return false
privKeys []*keys.Key
}

func (l *lighthouseKeystore) Encode(o *output) error {
// If the cache dir exists, just copy to destination.
if isExistingDir(l.cacheDir) {
return o.WriteDir(l.cacheDir)
}

// If the cache dir doesn't exist, set dst as the cache dir to write the keys there first.
oldDst := o.dst
o.dst = l.cacheDir

for _, key := range l.privKeys {
encryptor := keystorev4.New()
cryptoFields, err := encryptor.Encrypt(key.Marshal(), secret)
if err != nil {
return err
}

id, _ := uuid.GenerateUUID()

pubKeyHex := "0x" + hex.EncodeToString(key.PublicKey().Marshal())
item := map[string]interface{}{
"crypto": cryptoFields,
"uuid": id,
"pubkey": pubKeyHex[2:], // without 0x in the json file
"version": 4,
"description": "",
}
valJSON, err := json.MarshalIndent(item, "", "\t")
if err != nil {
return err
}
pubKeyHex := "0x" + hex.EncodeToString(key.Pub.Marshal())

if err := o.WriteBatch(map[string]interface{}{
"validators/" + pubKeyHex + "/voting-keystore.json": valJSON,
"secrets/" + pubKeyHex: secret,
"validators/" + pubKeyHex + "/voting-keystore.json": key.Keystore,
"secrets/" + pubKeyHex: keys.DefaultSecret,
}); err != nil {
return err
}
}

// Restore the dst and write from the cache.
o.dst = oldDst
return o.WriteDir(l.cacheDir)
return nil
}

type encObject interface {
Expand Down
39 changes: 39 additions & 0 deletions tools/pregenerate_bls_keys/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package main

import (
"encoding/json"
"fmt"
"log"

"github.com/OffchainLabs/prysm/v6/runtime/interop"
"github.com/flashbots/builder-playground/utils/keys"
)

func main() {
if err := generateKeys(); err != nil {
log.Fatal(err.Error())
}
}

func generateKeys() error {
priv, _, err := interop.DeterministicallyGenerateKeys(0, 100)
if err != nil {
return err
}

keysResult := []*keys.Key{}
for i := 0; i < len(priv); i++ {
key, err := keys.NewKey(priv[i], keys.DefaultSecret)
if err != nil {
return err
}
keysResult = append(keysResult, key)
}

data, err := json.Marshal(keysResult)
if err != nil {
panic(err)
}
fmt.Println(string(data))
return nil
}
1 change: 1 addition & 0 deletions utils/keys/fixtures/bls_keys.json

Large diffs are not rendered by default.

118 changes: 118 additions & 0 deletions utils/keys/keys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package keys

import (
"encoding/hex"
"encoding/json"
"fmt"

_ "embed"

"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/hashicorp/go-uuid"
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
)

var DefaultSecret = "secret"

//go:embed fixtures/bls_keys.json
var pregeneratesBLSKeys []byte

type Key struct {
Priv bls.SecretKey
Pub bls.PublicKey
Keystore []byte
}

func NewKey(priv bls.SecretKey, secret string) (*Key, error) {
store, err := GenerateKeystore(priv, secret)
if err != nil {
return nil, err
}

valJSON, err := json.Marshal(store)
if err != nil {
return nil, err
}

key := &Key{
Priv: priv,
Pub: priv.PublicKey(),
Keystore: []byte(valJSON),
}
return key, nil
}

func (k *Key) MarshalJSON() ([]byte, error) {
type keyJSON struct {
Priv string `json:"priv"`
Pub string `json:"pub"`
Keystore string `json:"keystore"`
}

return json.Marshal(&keyJSON{
Priv: fmt.Sprintf("%x", k.Priv.Marshal()),
Pub: fmt.Sprintf("%x", k.Pub.Marshal()),
Keystore: string(k.Keystore),
})
}

func (k *Key) UnmarshalJSON(data []byte) error {
type keyJSON struct {
Priv string `json:"priv"`
Pub string `json:"pub"`
Keystore string `json:"keystore"`
}

var kj keyJSON
if err := json.Unmarshal(data, &kj); err != nil {
return err
}

privBytes, err := hex.DecodeString(kj.Priv)
if err != nil {
return err
}
if k.Priv, err = bls.SecretKeyFromBytes(privBytes); err != nil {
return err
}

pubBytes, err := hex.DecodeString(kj.Pub)
if err != nil {
return err
}
if k.Pub, err = bls.PublicKeyFromBytes(pubBytes); err != nil {
return err
}

k.Keystore = []byte(kj.Keystore)
return nil
}

func GetPregeneratedBLSKeys() ([]*Key, error) {
var keys []*Key
if err := json.Unmarshal(pregeneratesBLSKeys, &keys); err != nil {
return nil, err
}
return keys, nil
}

func GenerateKeystore(key bls.SecretKey, secret string) (map[string]interface{}, error) {
encryptor := keystorev4.New()
cryptoFields, err := encryptor.Encrypt(key.Marshal(), secret)
if err != nil {
return nil, err
}

id, _ := uuid.GenerateUUID()

pubKeyHex := "0x" + hex.EncodeToString(key.PublicKey().Marshal())
item := map[string]interface{}{
"crypto": cryptoFields,
"uuid": id,
"pubkey": pubKeyHex[2:], // without 0x in the json file
"version": 4,
"description": "",
}

return item, nil
}
58 changes: 58 additions & 0 deletions utils/keys/keys_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package keys

import (
"encoding/json"
"testing"

"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/stretchr/testify/require"
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
)

func TestKeystoreEncoding(t *testing.T) {
blsKey, err := bls.RandKey()
require.NoError(t, err)

key, err := NewKey(blsKey, DefaultSecret)
require.NoError(t, err)

res, err := decodeKeystore(key, DefaultSecret)
require.NoError(t, err)
require.Equal(t, res, key.Priv.Marshal())

// Try to marshal/unmarhsal it and it should still decode properly
keyMarshal, err := key.MarshalJSON()
require.NoError(t, err)

var key1 Key
require.NoError(t, key1.UnmarshalJSON(keyMarshal))

_, err = decodeKeystore(&key1, DefaultSecret)
require.NoError(t, err)
}

func TestKeystoreBuiltin(t *testing.T) {
keys, err := GetPregeneratedBLSKeys()
require.NoError(t, err)
require.Len(t, keys, 100)

for _, key := range keys {
res, err := decodeKeystore(key, DefaultSecret)
require.NoError(t, err)
require.Equal(t, res, key.Priv.Marshal())
}
}

func decodeKeystore(key *Key, secret string) ([]byte, error) {
var input map[string]interface{}
if err := json.Unmarshal(key.Keystore, &input); err != nil {
return nil, err
}

encryptor := keystorev4.New()
decrypted, err := encryptor.Decrypt(input["crypto"].(map[string]interface{}), secret)
if err != nil {
return nil, err
}
return decrypted, nil
}