diff --git a/.circleci/config.yml b/.circleci/config.yml index d68676f6c683..98d291d13351 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,7 +12,7 @@ end-to-end-defaults: &end-to-end-defaults docker: - image: celohq/node10-gcloud environment: - CELO_MONOREPO_BRANCH_TO_TEST: master + CELO_MONOREPO_BRANCH_TO_TEST: kobigurk/epoch_data jobs: unit-tests: diff --git a/accounts/accounts.go b/accounts/accounts.go index b7dee52b0739..74fd17bc9513 100644 --- a/accounts/accounts.go +++ b/accounts/accounts.go @@ -24,6 +24,7 @@ import ( ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "github.com/ethereum/go-ethereum/event" ) @@ -103,8 +104,8 @@ type Wallet interface { // the needed details via SignHashWithPassphrase, or by other means (e.g. unlock // the account in a keystore). SignHash(account Account, hash []byte) ([]byte, error) - SignHashBLS(account Account, hash []byte) ([]byte, error) - SignMessageBLS(account Account, msg []byte, extraData []byte) ([]byte, error) + SignHashBLS(account Account, hash []byte) (blscrypto.SerializedSignature, error) + SignMessageBLS(account Account, msg []byte, extraData []byte) (blscrypto.SerializedSignature, error) GenerateProofOfPossession(account Account, address common.Address) ([]byte, []byte, error) GenerateProofOfPossessionBLS(account Account, address common.Address) ([]byte, []byte, error) GetPublicKey(account Account) (*ecdsa.PublicKey, error) diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index 0878d6ac6cfe..8fd0716110fa 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -287,72 +287,72 @@ func (ks *KeyStore) SignHash(a accounts.Account, hash []byte) ([]byte, error) { return crypto.Sign(hash, unlockedKey.PrivateKey) } -func (ks *KeyStore) SignHashBLS(a accounts.Account, hash []byte) ([]byte, error) { +func (ks *KeyStore) SignHashBLS(a accounts.Account, hash []byte) (blscrypto.SerializedSignature, error) { // Look up the key to sign with and abort if it cannot be found ks.mu.RLock() defer ks.mu.RUnlock() unlockedKey, found := ks.unlocked[a.Address] if !found { - return nil, ErrLocked + return blscrypto.SerializedSignature{}, ErrLocked } privateKeyBytes, err := blscrypto.ECDSAToBLS(unlockedKey.PrivateKey) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer privateKey.Destroy() signature, err := privateKey.SignMessage(hash, []byte{}, false) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer signature.Destroy() signatureBytes, err := signature.Serialize() if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } -func (ks *KeyStore) SignMessageBLS(a accounts.Account, msg []byte, extraData []byte) ([]byte, error) { +func (ks *KeyStore) SignMessageBLS(a accounts.Account, msg []byte, extraData []byte) (blscrypto.SerializedSignature, error) { // Look up the key to sign with and abort if it cannot be found ks.mu.RLock() defer ks.mu.RUnlock() unlockedKey, found := ks.unlocked[a.Address] if !found { - return nil, ErrLocked + return blscrypto.SerializedSignature{}, ErrLocked } privateKeyBytes, err := blscrypto.ECDSAToBLS(unlockedKey.PrivateKey) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer privateKey.Destroy() signature, err := privateKey.SignMessage(msg, extraData, true) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer signature.Destroy() signatureBytes, err := signature.Serialize() if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } func (ks *KeyStore) GenerateProofOfPossession(a accounts.Account, address common.Address) ([]byte, []byte, error) { diff --git a/accounts/keystore/wallet.go b/accounts/keystore/wallet.go index a54655e99363..8c694eeaa888 100644 --- a/accounts/keystore/wallet.go +++ b/accounts/keystore/wallet.go @@ -18,6 +18,7 @@ package keystore import ( "crypto/ecdsa" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "github.com/ethereum/go-ethereum/log" "math/big" @@ -119,21 +120,21 @@ func (w *keystoreWallet) GetPublicKey(account accounts.Account) (*ecdsa.PublicKe return w.keystore.GetPublicKey(account) } -func (w *keystoreWallet) SignHashBLS(account accounts.Account, hash []byte) ([]byte, error) { +func (w *keystoreWallet) SignHashBLS(account accounts.Account, hash []byte) (blscrypto.SerializedSignature, error) { // Make sure the requested account is contained within if !w.Contains(account) { log.Debug(accounts.ErrUnknownAccount.Error(), "account", account) - return nil, accounts.ErrUnknownAccount + return blscrypto.SerializedSignature{}, accounts.ErrUnknownAccount } // Account seems valid, request the keystore to sign return w.keystore.SignHashBLS(account, hash) } -func (w *keystoreWallet) SignMessageBLS(account accounts.Account, msg []byte, extraData []byte) ([]byte, error) { +func (w *keystoreWallet) SignMessageBLS(account accounts.Account, msg []byte, extraData []byte) (blscrypto.SerializedSignature, error) { // Make sure the requested account is contained within if !w.Contains(account) { log.Debug(accounts.ErrUnknownAccount.Error(), "account", account) - return nil, accounts.ErrUnknownAccount + return blscrypto.SerializedSignature{}, accounts.ErrUnknownAccount } // Account seems valid, request the keystore to sign return w.keystore.SignMessageBLS(account, msg, extraData) diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index 69029c18d4c3..f47700cd3d3f 100644 --- a/accounts/usbwallet/wallet.go +++ b/accounts/usbwallet/wallet.go @@ -21,6 +21,7 @@ import ( "context" "crypto/ecdsa" "fmt" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "io" "math/big" "sync" @@ -510,12 +511,12 @@ func (w *wallet) GetPublicKey(account accounts.Account) (*ecdsa.PublicKey, error return nil, accounts.ErrNotSupported } -func (w *wallet) SignHashBLS(account accounts.Account, hash []byte) ([]byte, error) { - return nil, accounts.ErrNotSupported +func (w *wallet) SignHashBLS(account accounts.Account, hash []byte) (blscrypto.SerializedSignature, error) { + return blscrypto.SerializedSignature{}, accounts.ErrNotSupported } -func (w *wallet) SignMessageBLS(account accounts.Account, msg []byte, extraData []byte) ([]byte, error) { - return nil, accounts.ErrNotSupported +func (w *wallet) SignMessageBLS(account accounts.Account, msg []byte, extraData []byte) (blscrypto.SerializedSignature, error) { + return blscrypto.SerializedSignature{}, accounts.ErrNotSupported } func (w *wallet) GenerateProofOfPossession(account accounts.Account, address common.Address) ([]byte, []byte, error) { diff --git a/consensus/istanbul/backend.go b/consensus/istanbul/backend.go index c62d0f48ef5c..f326b6776d08 100644 --- a/consensus/istanbul/backend.go +++ b/consensus/istanbul/backend.go @@ -17,6 +17,7 @@ package istanbul import ( + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "math/big" "time" @@ -30,9 +31,13 @@ import ( // backing account. type SignerFn func(accounts.Account, []byte) ([]byte, error) +// BLSSignerFn is a signer callback function to request a hash to be signed by a +// backing account using BLS. +type BLSSignerFn func(accounts.Account, []byte) (blscrypto.SerializedSignature, error) + // MessageSignerFn is a signer callback function to request a raw message to // be signed by a backing account. -type MessageSignerFn func(accounts.Account, []byte, []byte) ([]byte, error) +type MessageSignerFn func(accounts.Account, []byte, []byte) (blscrypto.SerializedSignature, error) // Backend provides application specific functions for Istanbul core type Backend interface { @@ -41,6 +46,7 @@ type Backend interface { // Validators returns the validator set Validators(proposal Proposal) ValidatorSet + NextBlockValidators(proposal Proposal) (ValidatorSet, error) // EventMux returns the event mux in backend EventMux() *event.TypeMux @@ -53,7 +59,7 @@ type Backend interface { // Commit delivers an approved proposal to backend. // The delivered proposal will be put into blockchain. - Commit(proposal Proposal, aggregatedSeal types.IstanbulAggregatedSeal) error + Commit(proposal Proposal, aggregatedSeal types.IstanbulAggregatedSeal, aggregatedEpochValidatorSetSeal types.IstanbulEpochValidatorSetSeal) error // Verify verifies the proposal. If a consensus.ErrFutureBlock error is returned, // the time difference of the proposal and current time is also returned. @@ -61,7 +67,8 @@ type Backend interface { // Sign signs input data with the backend's private key Sign([]byte) ([]byte, error) - SignBlockHeader([]byte) ([]byte, error) + SignBlockHeader([]byte) (blscrypto.SerializedSignature, error) + SignBLSWithCompositeHash([]byte) (blscrypto.SerializedSignature, error) // CheckSignature verifies the signature by checking if it's signed by // the given validator @@ -89,5 +96,5 @@ type Backend interface { RefreshValPeers(valset ValidatorSet) // Authorize injects a private key into the consensus engine. - Authorize(address common.Address, signFn SignerFn, signHashBLSFn SignerFn, signMessageBLSFn MessageSignerFn) + Authorize(address common.Address, signFn SignerFn, signHashBLSFn BLSSignerFn, signMessageBLSFn MessageSignerFn) } diff --git a/consensus/istanbul/backend/backend.go b/consensus/istanbul/backend/backend.go index 37def88e4229..cfba8e969918 100644 --- a/consensus/istanbul/backend/backend.go +++ b/consensus/istanbul/backend/backend.go @@ -18,6 +18,8 @@ package backend import ( "errors" + "fmt" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "math/big" "sync" "time" @@ -148,7 +150,7 @@ type Backend struct { address common.Address // Ethereum address of the signing key signFn istanbul.SignerFn // Signer function to authorize hashes with - signHashBLSFn istanbul.SignerFn // Signer function to authorize hashes using BLS with + signHashBLSFn istanbul.BLSSignerFn // Signer function to authorize hashes using BLS with signMessageBLSFn istanbul.MessageSignerFn // Signer function to authorize messages using BLS with signFnMu sync.RWMutex // Protects the signer fields @@ -240,7 +242,7 @@ func (sb *Backend) SendDelegateSignMsgToProxiedValidator(msg []byte) error { } // Authorize implements istanbul.Backend.Authorize -func (sb *Backend) Authorize(address common.Address, signFn istanbul.SignerFn, signHashBLSFn istanbul.SignerFn, signMessageBLSFn istanbul.MessageSignerFn) { +func (sb *Backend) Authorize(address common.Address, signFn istanbul.SignerFn, signHashBLSFn istanbul.BLSSignerFn, signMessageBLSFn istanbul.MessageSignerFn) { sb.signFnMu.Lock() defer sb.signFnMu.Unlock() @@ -272,6 +274,38 @@ func (sb *Backend) ParentBlockValidators(proposal istanbul.Proposal) istanbul.Va return sb.getOrderedValidators(proposal.Number().Uint64()-1, proposal.ParentHash()) } +func (sb *Backend) NextBlockValidators(proposal istanbul.Proposal) (istanbul.ValidatorSet, error) { + istExtra, err := types.ExtractIstanbulExtra(proposal.Header()) + if err != nil { + return nil, err + } + + // There was no change + if len(istExtra.AddedValidators) == 0 && istExtra.RemovedValidators.BitLen() == 0 { + return sb.ParentBlockValidators(proposal), nil + } + + snap, err := sb.snapshot(sb.chain, proposal.Number().Uint64()-1, common.Hash{}, nil) + if err != nil { + return nil, err + } + snap = snap.copy() + + addedValidators, err := istanbul.CombineIstanbulExtraToValidatorData(istExtra.AddedValidators, istExtra.AddedValidatorsPublicKeys) + if err != nil { + return nil, err + } + + if !snap.ValSet.RemoveValidators(istExtra.RemovedValidators) { + return nil, fmt.Errorf("could not obtain next block validators: failed at remove validators") + } + if !snap.ValSet.AddValidators(addedValidators) { + return nil, fmt.Errorf("could not obtain next block validators: failed at add validators") + } + + return snap.ValSet, nil +} + func (sb *Backend) GetValidators(blockNumber *big.Int, headerHash common.Hash) []istanbul.Validator { validatorSet := sb.getValidators(blockNumber.Uint64(), headerHash) return validatorSet.List() @@ -380,7 +414,7 @@ func (sb *Backend) Gossip(destAddresses []common.Address, payload []byte, ethMsg } // Commit implements istanbul.Backend.Commit -func (sb *Backend) Commit(proposal istanbul.Proposal, aggregatedSeal types.IstanbulAggregatedSeal) error { +func (sb *Backend) Commit(proposal istanbul.Proposal, aggregatedSeal types.IstanbulAggregatedSeal, aggregatedEpochValidatorSetSeal types.IstanbulEpochValidatorSetSeal) error { // Check if the proposal is a valid block block := &types.Block{} block, ok := proposal.(*types.Block) @@ -397,6 +431,9 @@ func (sb *Backend) Commit(proposal istanbul.Proposal, aggregatedSeal types.Istan } // update block's header block = block.WithSeal(h) + block = block.WithEpochSnarkData(&types.EpochSnarkData{ + Signature: aggregatedEpochValidatorSetSeal.Signature, + }) sb.logger.Info("Committed", "address", sb.Address(), "round", aggregatedSeal.Round.Uint64(), "hash", proposal.Hash(), "number", proposal.Number().Uint64()) // - if the proposed and committed blocks are the same, send the proposed hash @@ -459,7 +496,7 @@ func (sb *Backend) Verify(proposal istanbul.Proposal) (time.Duration, error) { err = sb.VerifyHeader(sb.chain, block.Header(), false) - // ignore errEmptyCommittedSeals error because we don't have the committed seals yet + // ignore errEmptyAggregatedSeal error because we don't have the committed seals yet if err != nil && err != errEmptyAggregatedSeal { if err == consensus.ErrFutureBlock { return time.Unix(block.Header().Time.Int64(), 0).Sub(now()), consensus.ErrFutureBlock @@ -541,7 +578,7 @@ func (sb *Backend) verifyValSetDiff(proposal istanbul.Proposal, block *types.Blo addedValidators, removedValidators := istanbul.ValidatorSetDiff(oldValSet, newValSet) addedValidatorsAddresses := make([]common.Address, 0, len(addedValidators)) - addedValidatorsPublicKeys := make([][]byte, 0, len(addedValidators)) + addedValidatorsPublicKeys := make([]blscrypto.SerializedPublicKey, 0, len(addedValidators)) for _, val := range addedValidators { addedValidatorsAddresses = append(addedValidatorsAddresses, val.Address) addedValidatorsPublicKeys = append(addedValidatorsPublicKeys, val.BLSPublicKey) @@ -567,15 +604,28 @@ func (sb *Backend) Sign(data []byte) ([]byte, error) { return sb.signFn(accounts.Account{Address: sb.address}, hashData) } -func (sb *Backend) SignBlockHeader(data []byte) ([]byte, error) { +func (sb *Backend) SignBlockHeader(data []byte) (blscrypto.SerializedSignature, error) { if sb.signHashBLSFn == nil { - return nil, errInvalidSigningFn + return blscrypto.SerializedSignature{}, errInvalidSigningFn } sb.signFnMu.RLock() defer sb.signFnMu.RUnlock() return sb.signHashBLSFn(accounts.Account{Address: sb.address}, data) } +func (sb *Backend) SignBLSWithCompositeHash(data []byte) (blscrypto.SerializedSignature, error) { + if sb.signMessageBLSFn == nil { + return blscrypto.SerializedSignature{}, errInvalidSigningFn + } + sb.signFnMu.RLock() + defer sb.signFnMu.RUnlock() + // Currently, ExtraData is unused. In the future, it could include data that could be used to introduce + // "firmware-level" protection. Such data could include data that the SNARK doesn't necessarily need, + // such as the block number, which can be used by a hardware wallet to see that the block number + // is incrementing, without having to perform the two-level hashing, just one-level fast hashing. + return sb.signMessageBLSFn(accounts.Account{Address: sb.address}, data, []byte{}) +} + // CheckSignature implements istanbul.Backend.CheckSignature func (sb *Backend) CheckSignature(data []byte, address common.Address, sig []byte) error { signer, err := istanbul.GetSignatureAddress(data, sig) diff --git a/consensus/istanbul/backend/backend_test.go b/consensus/istanbul/backend/backend_test.go index 44e5db066760..e0853e344e4f 100644 --- a/consensus/istanbul/backend/backend_test.go +++ b/consensus/istanbul/backend/backend_test.go @@ -156,7 +156,7 @@ func TestCommit(t *testing.T) { }() backend.proposedBlockHash = expBlock.Hash() - if err := backend.Commit(expBlock, types.IstanbulAggregatedSeal{Round: big.NewInt(0), Bitmap: big.NewInt(0), Signature: test.expectedSignature}); err != nil { + if err := backend.Commit(expBlock, types.IstanbulAggregatedSeal{Round: big.NewInt(0), Bitmap: big.NewInt(0), Signature: test.expectedSignature}, types.IstanbulEpochValidatorSetSeal{Signature: nil}); err != nil { if err != test.expectedErr { t.Errorf("error mismatch: have %v, want %v", err, test.expectedErr) } @@ -248,56 +248,56 @@ func signerFn(_ accounts.Account, data []byte) ([]byte, error) { return crypto.Sign(data, key) } -func signerBLSHashFn(_ accounts.Account, data []byte) ([]byte, error) { +func signerBLSHashFn(_ accounts.Account, data []byte) (blscrypto.SerializedSignature, error) { key, _ := generatePrivateKey() privateKeyBytes, err := blscrypto.ECDSAToBLS(key) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer privateKey.Destroy() signature, err := privateKey.SignMessage(data, []byte{}, false) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer signature.Destroy() signatureBytes, err := signature.Serialize() if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } -func signerBLSMessageFn(_ accounts.Account, data []byte, extraData []byte) ([]byte, error) { +func signerBLSMessageFn(_ accounts.Account, data []byte, extraData []byte) (blscrypto.SerializedSignature, error) { key, _ := generatePrivateKey() privateKeyBytes, err := blscrypto.ECDSAToBLS(key) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer privateKey.Destroy() signature, err := privateKey.SignMessage(data, extraData, true) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer signature.Destroy() signatureBytes, err := signature.Serialize() if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } func newBackend() (b *Backend) { diff --git a/consensus/istanbul/backend/engine.go b/consensus/istanbul/backend/engine.go index d3a6b528db40..942be28479a5 100644 --- a/consensus/istanbul/backend/engine.go +++ b/consensus/istanbul/backend/engine.go @@ -325,7 +325,7 @@ func (sb *Backend) verifyAggregatedSeal(headerHash common.Hash, validators istan proposalSeal := istanbulCore.PrepareCommittedSeal(headerHash, aggregatedSeal.Round) // Find which public keys signed from the provided validator set - publicKeys := [][]byte{} + publicKeys := []blscrypto.SerializedPublicKey{} for i := 0; i < validators.Size(); i++ { if aggregatedSeal.Bitmap.Bit(i) == 1 { pubKey := validators.GetByIndex(uint64(i)).BLSPublicKey() @@ -920,12 +920,11 @@ func ecrecover(header *types.Header) (common.Address, error) { func writeEmptyIstanbulExtra(header *types.Header) error { extra := types.IstanbulExtra{ AddedValidators: []common.Address{}, - AddedValidatorsPublicKeys: [][]byte{}, + AddedValidatorsPublicKeys: []blscrypto.SerializedPublicKey{}, RemovedValidators: big.NewInt(0), Seal: []byte{}, AggregatedSeal: types.IstanbulAggregatedSeal{}, ParentAggregatedSeal: types.IstanbulAggregatedSeal{}, - EpochData: []byte{}, } payload, err := rlp.EncodeToBytes(&extra) if err != nil { diff --git a/consensus/istanbul/backend/engine_test.go b/consensus/istanbul/backend/engine_test.go index 2ed825248a78..26587034d191 100644 --- a/consensus/istanbul/backend/engine_test.go +++ b/consensus/istanbul/backend/engine_test.go @@ -59,56 +59,56 @@ func newBlockChain(n int, isFullChain bool) (*core.BlockChain, *Backend) { return crypto.Sign(data, nodeKeys[0]) } - signerBLSHashFn := func(_ accounts.Account, data []byte) ([]byte, error) { + signerBLSHashFn := func(_ accounts.Account, data []byte) (blscrypto.SerializedSignature, error) { key := nodeKeys[0] privateKeyBytes, err := blscrypto.ECDSAToBLS(key) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer privateKey.Destroy() signature, err := privateKey.SignMessage(data, []byte{}, false) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer signature.Destroy() signatureBytes, err := signature.Serialize() if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } - signerBLSMessageFn := func(_ accounts.Account, data []byte, extraData []byte) ([]byte, error) { + signerBLSMessageFn := func(_ accounts.Account, data []byte, extraData []byte) (blscrypto.SerializedSignature, error) { key := nodeKeys[0] privateKeyBytes, err := blscrypto.ECDSAToBLS(key) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer privateKey.Destroy() signature, err := privateKey.SignMessage(data, extraData, true) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer signature.Destroy() signatureBytes, err := signature.Serialize() if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } b, _ := New(config, memDB).(*Backend) @@ -153,54 +153,54 @@ func newBlockChain(n int, isFullChain bool) (*core.BlockChain, *Backend) { signerFn := func(_ accounts.Account, data []byte) ([]byte, error) { return crypto.Sign(data, key) } - signerBLSHashFn := func(_ accounts.Account, data []byte) ([]byte, error) { + signerBLSHashFn := func(_ accounts.Account, data []byte) (blscrypto.SerializedSignature, error) { privateKeyBytes, err := blscrypto.ECDSAToBLS(key) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer privateKey.Destroy() signature, err := privateKey.SignMessage(data, []byte{}, false) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer signature.Destroy() signatureBytes, err := signature.Serialize() if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } - signerBLSMessageFn := func(_ accounts.Account, data []byte, extraData []byte) ([]byte, error) { + signerBLSMessageFn := func(_ accounts.Account, data []byte, extraData []byte) (blscrypto.SerializedSignature, error) { privateKeyBytes, err := blscrypto.ECDSAToBLS(key) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer privateKey.Destroy() signature, err := privateKey.SignMessage(data, extraData, true) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer signature.Destroy() signatureBytes, err := signature.Serialize() if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } b.Authorize(address, signerFn, signerBLSHashFn, signerBLSMessageFn) @@ -369,7 +369,7 @@ func TestSealCommittedOtherHash(t *testing.T) { if !ok { t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data)) } - engine.Commit(otherBlock, types.IstanbulAggregatedSeal{}) + engine.Commit(otherBlock, types.IstanbulAggregatedSeal{}, types.IstanbulEpochValidatorSetSeal{}) eventSub.Unsubscribe() } go eventLoop() @@ -662,31 +662,30 @@ func TestPrepareExtra(t *testing.T) { oldValidators := make([]istanbul.ValidatorData, 2) oldValidators[0] = istanbul.ValidatorData{ common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")), - make([]byte, blscrypto.PUBLICKEYBYTES), + blscrypto.SerializedPublicKey{}, } oldValidators[1] = istanbul.ValidatorData{ common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")), - make([]byte, blscrypto.PUBLICKEYBYTES), + blscrypto.SerializedPublicKey{}, } newValidators := make([]istanbul.ValidatorData, 2) newValidators[0] = istanbul.ValidatorData{ common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")), - make([]byte, blscrypto.PUBLICKEYBYTES), + blscrypto.SerializedPublicKey{}, } newValidators[1] = istanbul.ValidatorData{ common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")), - make([]byte, blscrypto.PUBLICKEYBYTES), + blscrypto.SerializedPublicKey{}, } extra, err := rlp.EncodeToBytes(&types.IstanbulExtra{ AddedValidators: []common.Address{}, - AddedValidatorsPublicKeys: [][]byte{}, + AddedValidatorsPublicKeys: []blscrypto.SerializedPublicKey{}, RemovedValidators: big.NewInt(0), Seal: []byte{}, AggregatedSeal: types.IstanbulAggregatedSeal{}, ParentAggregatedSeal: types.IstanbulAggregatedSeal{}, - EpochData: []byte{}, }) h := &types.Header{ Extra: append(make([]byte, types.IstanbulExtraVanity), extra...), @@ -730,12 +729,11 @@ func TestWriteSeal(t *testing.T) { common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")), common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")), }, - AddedValidatorsPublicKeys: [][]byte{}, + AddedValidatorsPublicKeys: []blscrypto.SerializedPublicKey{}, RemovedValidators: big.NewInt(12), // 1100, remove third and fourth validators Seal: []byte{}, AggregatedSeal: types.IstanbulAggregatedSeal{big.NewInt(0), []byte{}, big.NewInt(0)}, ParentAggregatedSeal: types.IstanbulAggregatedSeal{big.NewInt(0), []byte{}, big.NewInt(0)}, - EpochData: []byte{}, } istExtraRaw, err := rlp.EncodeToBytes(&istExtra) @@ -782,12 +780,11 @@ func TestWriteAggregatedSeal(t *testing.T) { common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")), common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")), }, - AddedValidatorsPublicKeys: [][]byte{}, + AddedValidatorsPublicKeys: []blscrypto.SerializedPublicKey{}, RemovedValidators: big.NewInt(12), // 1100, remove third and fourth validators Seal: []byte{}, AggregatedSeal: types.IstanbulAggregatedSeal{}, ParentAggregatedSeal: types.IstanbulAggregatedSeal{}, - EpochData: []byte{}, } istExtraRaw, err := rlp.EncodeToBytes(&istExtra) diff --git a/consensus/istanbul/backend/snapshot_test.go b/consensus/istanbul/backend/snapshot_test.go index 9881820f5987..7c3596b10b68 100644 --- a/consensus/istanbul/backend/snapshot_test.go +++ b/consensus/istanbul/backend/snapshot_test.go @@ -119,7 +119,7 @@ func convertValNamesToValidatorsData(accounts *testerAccountPool, valNames []str for i, valName := range valNames { returnArray[i] = istanbul.ValidatorData{ accounts.address(valName), - nil, + blscrypto.SerializedPublicKey{}, } } @@ -233,7 +233,7 @@ func TestValSetChange(t *testing.T) { for j, validator := range tt.validators { validators[j] = istanbul.ValidatorData{ accounts.address(validator), - nil, + blscrypto.SerializedPublicKey{}, } } @@ -271,56 +271,56 @@ func TestValSetChange(t *testing.T) { return crypto.Sign(data, privateKey) } - signerBLSHashFn := func(_ ethAccounts.Account, data []byte) ([]byte, error) { + signerBLSHashFn := func(_ ethAccounts.Account, data []byte) (blscrypto.SerializedSignature, error) { key := privateKey privateKeyBytes, err := blscrypto.ECDSAToBLS(key) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer privateKey.Destroy() signature, err := privateKey.SignMessage(data, []byte{}, false) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer signature.Destroy() signatureBytes, err := signature.Serialize() if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } - signerBLSMessageFn := func(_ ethAccounts.Account, data []byte, extraData []byte) ([]byte, error) { + signerBLSMessageFn := func(_ ethAccounts.Account, data []byte, extraData []byte) (blscrypto.SerializedSignature, error) { key := privateKey privateKeyBytes, err := blscrypto.ECDSAToBLS(key) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer privateKey.Destroy() signature, err := privateKey.SignMessage(data, extraData, true) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer signature.Destroy() signatureBytes, err := signature.Serialize() if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } engine.Authorize(address, signerFn, signerBLSHashFn, signerBLSMessageFn) @@ -352,11 +352,10 @@ func TestValSetChange(t *testing.T) { ist := &types.IstanbulExtra{ AddedValidators: convertValNames(accounts, valsetdiff.addedValidators), - AddedValidatorsPublicKeys: make([][]byte, len(valsetdiff.addedValidators)), + AddedValidatorsPublicKeys: make([]blscrypto.SerializedPublicKey, len(valsetdiff.addedValidators)), RemovedValidators: convertValNamesToRemovedValidators(accounts, oldVals, valsetdiff.removedValidators), AggregatedSeal: types.IstanbulAggregatedSeal{}, ParentAggregatedSeal: types.IstanbulAggregatedSeal{}, - EpochData: []byte{}, } payload, err := rlp.EncodeToBytes(&ist) @@ -394,7 +393,7 @@ func TestValSetChange(t *testing.T) { for j, validator := range tt.results { validators[j] = istanbul.ValidatorData{ accounts.address(validator), - nil, + blscrypto.SerializedPublicKey{}, } } result := snap.validators() @@ -421,11 +420,11 @@ func TestSaveAndLoad(t *testing.T) { ValSet: validator.NewSet([]istanbul.ValidatorData{ { common.BytesToAddress([]byte("1234567894")), - nil, + blscrypto.SerializedPublicKey{}, }, { common.BytesToAddress([]byte("1234567895")), - nil, + blscrypto.SerializedPublicKey{}, }, }), } diff --git a/consensus/istanbul/backend/test_util.go b/consensus/istanbul/backend/test_util.go index 62ea38dbb907..d8b51df5db89 100644 --- a/consensus/istanbul/backend/test_util.go +++ b/consensus/istanbul/backend/test_util.go @@ -2,6 +2,7 @@ package backend import ( "bytes" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/istanbul" @@ -17,10 +18,10 @@ func AppendValidatorsToGenesisBlock(genesis *core.Genesis, validators []istanbul genesis.ExtraData = genesis.ExtraData[:types.IstanbulExtraVanity] addrs := []common.Address{} - publicKeys := [][]byte{} + publicKeys := []blscrypto.SerializedPublicKey{} for i := range validators { - if validators[i].BLSPublicKey == nil { + if (validators[i].BLSPublicKey == blscrypto.SerializedPublicKey{}) { panic("BLSPublicKey is nil") } addrs = append(addrs, validators[i].Address) diff --git a/consensus/istanbul/core/backlog_test.go b/consensus/istanbul/core/backlog_test.go index eef90ed8b250..79bba57d61d7 100644 --- a/consensus/istanbul/core/backlog_test.go +++ b/consensus/istanbul/core/backlog_test.go @@ -18,6 +18,7 @@ package core import ( "fmt" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "math/big" "reflect" "testing" @@ -226,8 +227,8 @@ func TestStoreBacklog(t *testing.T) { Round: big.NewInt(12), Sequence: big.NewInt(11), } - p1 := validator.New(common.BytesToAddress([]byte("12345667890")), []byte{}) - p2 := validator.New(common.BytesToAddress([]byte("47324349949")), []byte{}) + p1 := validator.New(common.BytesToAddress([]byte("12345667890")), blscrypto.SerializedPublicKey{}) + p2 := validator.New(common.BytesToAddress([]byte("47324349949")), blscrypto.SerializedPublicKey{}) // push messages preprepare := &istanbul.Preprepare{ @@ -333,6 +334,7 @@ func TestProcessFutureBacklog(t *testing.T) { Round: big.NewInt(10), Sequence: big.NewInt(10), } + committedSubject := &istanbul.CommittedSubject{ Subject: &istanbul.Subject{ View: v, diff --git a/consensus/istanbul/core/commit.go b/consensus/istanbul/core/commit.go index a5fecaa78161..1702fb98a304 100644 --- a/consensus/istanbul/core/commit.go +++ b/consensus/istanbul/core/commit.go @@ -30,15 +30,32 @@ func (c *core) sendCommit() { c.broadcastCommit(sub) } -func (c *core) generateCommittedSeal(sub *istanbul.Subject) ([]byte, error) { +func (c *core) generateCommittedSeal(sub *istanbul.Subject) (blscrypto.SerializedSignature, error) { seal := PrepareCommittedSeal(sub.Digest, sub.View.Round) committedSeal, err := c.backend.SignBlockHeader(seal) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } return committedSeal, nil } +func (c *core) generateEpochValidatorSetData(blockNumber uint64, newValSet istanbul.ValidatorSet) ([]byte, error) { + if !istanbul.IsLastBlockOfEpoch(blockNumber, c.config.Epoch) { + return nil, errNotLastBlockInEpoch + } + blsPubKeys := []blscrypto.SerializedPublicKey{} + for _, v := range newValSet.List() { + blsPubKeys = append(blsPubKeys, v.BLSPublicKey()) + } + maxNonSignersPlusOne := uint32(newValSet.Size() - newValSet.MinQuorumSize() + 1) + epochData, err := blscrypto.EncodeEpochSnarkData(blsPubKeys, maxNonSignersPlusOne, uint16(istanbul.GetEpochNumber(blockNumber, c.config.Epoch))) + if err != nil { + return nil, err + } + + return epochData, nil +} + func (c *core) broadcastCommit(sub *istanbul.Subject) { logger := c.newLogger("func", "broadcastCommit") @@ -48,9 +65,30 @@ func (c *core) broadcastCommit(sub *istanbul.Subject) { return } + currentBlockNumber := c.current.Proposal().Number().Uint64() + newValSet, err := c.backend.NextBlockValidators(c.current.Proposal()) + if err != nil { + logger.Error("Failed to get next block's validators", "err", err) + return + } + epochValidatorSetData, err := c.generateEpochValidatorSetData(currentBlockNumber, newValSet) + if err != nil && err != errNotLastBlockInEpoch { + logger.Error("Failed to create epoch validator set data", "err", err) + return + } + var epochValidatorSetSeal blscrypto.SerializedSignature + if err == nil { + epochValidatorSetSeal, err = c.backend.SignBLSWithCompositeHash(epochValidatorSetData[:]) + if err != nil { + logger.Error("Failed to sign epoch validator set seal", "err", err) + return + } + } + committedSub := &istanbul.CommittedSubject{ - Subject: sub, - CommittedSeal: committedSeal, + Subject: sub, + CommittedSeal: committedSeal[:], + EpochValidatorSetSeal: epochValidatorSetSeal[:], } encodedCommittedSubject, err := Encode(committedSub) if err != nil { @@ -105,6 +143,12 @@ func (c *core) handleCheckedCommitForPreviousSequence(msg *istanbul.Message, com if err := c.verifyCommittedSeal(commit, validator); err != nil { return errInvalidCommittedSeal } + if headBlock.Number().Uint64() > 0 { + if err := c.verifyEpochValidatorSetSeal(commit, headBlock.Number().Uint64(), c.current.ValidatorSet(), validator); err != nil { + return errInvalidEpochValidatorSetSeal + } + } + // Ensure that the commit's digest (ie the received proposal's hash) matches the head block's hash if headBlock.Number().Uint64() > 0 && commit.Subject.Digest != headBlock.Hash() { logger.Debug("Received a commit message for the previous sequence with an unexpected hash", "expected", headBlock.Hash().String(), "received", commit.Subject.Digest.String()) @@ -130,6 +174,15 @@ func (c *core) handleCheckedCommitForCurrentSequence(msg *istanbul.Message, comm return errInvalidCommittedSeal } + newValSet, err := c.backend.NextBlockValidators(c.current.Proposal()) + if err != nil { + return err + } + + if err := c.verifyEpochValidatorSetSeal(commit, c.current.Proposal().Number().Uint64(), newValSet, validator); err != nil { + return errInvalidEpochValidatorSetSeal + } + // ensure that the commit is in the current proposal if err := c.verifyCommit(commit); err != nil { return err @@ -191,3 +244,18 @@ func (c *core) verifyCommittedSeal(comSub *istanbul.CommittedSubject, src istanb seal := PrepareCommittedSeal(comSub.Subject.Digest, comSub.Subject.View.Round) return blscrypto.VerifySignature(src.BLSPublicKey(), seal, []byte{}, comSub.CommittedSeal, false) } + +// verifyEpochValidatorSetSeal verifies the epoch validator set seal in the received COMMIT message +func (c *core) verifyEpochValidatorSetSeal(comSub *istanbul.CommittedSubject, blockNumber uint64, newValSet istanbul.ValidatorSet, src istanbul.Validator) error { + if blockNumber == 0 { + return nil + } + epochData, err := c.generateEpochValidatorSetData(blockNumber, newValSet) + if err != nil { + if err == errNotLastBlockInEpoch { + return nil + } + return err + } + return blscrypto.VerifySignature(src.BLSPublicKey(), epochData[:], []byte{}, comSub.EpochValidatorSetSeal, true) +} diff --git a/consensus/istanbul/core/commit_test.go b/consensus/istanbul/core/commit_test.go index 89417662c00b..adcacd47da68 100644 --- a/consensus/istanbul/core/commit_test.go +++ b/consensus/istanbul/core/commit_test.go @@ -170,7 +170,7 @@ func TestHandleCommit(t *testing.T) { sys := NewTestSystemWithBackend(N, F) for i, backend := range sys.backends { - backend.Commit(newTestProposalWithNum(3), types.IstanbulAggregatedSeal{}) + backend.Commit(newTestProposalWithNum(3), types.IstanbulAggregatedSeal{}, types.IstanbulEpochValidatorSetSeal{}) c := backend.engine.(*core) if i == 0 { // replica 0 is the proposer diff --git a/consensus/istanbul/core/core.go b/consensus/istanbul/core/core.go index 82d8cf57b5b2..1a46386b2b20 100644 --- a/consensus/istanbul/core/core.go +++ b/consensus/istanbul/core/core.go @@ -304,7 +304,14 @@ func (c *core) commit() error { c.waitForDesiredRound(nextRound) return nil } - if err := c.backend.Commit(proposal, aggregatedSeal); err != nil { + aggregatedEpochValidatorSetSeal, err := GetAggregatedEpochValidatorSetSeal(c.current.Commits()) + if err != nil { + nextRound := new(big.Int).Add(c.current.Round(), common.Big1) + c.logger.Warn("Error on commit, waiting for desired round", "reason", "GetAggregatedEpochValidatorSetSeal", "err", err, "desired_round", nextRound) + c.waitForDesiredRound(nextRound) + return nil + } + if err := c.backend.Commit(proposal, aggregatedSeal, aggregatedEpochValidatorSetSeal); err != nil { nextRound := new(big.Int).Add(c.current.Round(), common.Big1) c.logger.Warn("Error on commit, waiting for desired round", "reason", "backend.Commit", "err", err, "desired_round", nextRound) c.waitForDesiredRound(nextRound) @@ -314,6 +321,28 @@ func (c *core) commit() error { return nil } +// GetAggregatedEpochValidatorSetSeal aggregates all the given seals for the SNARK-friendly epoch encoding +// to a bls aggregated signature +func GetAggregatedEpochValidatorSetSeal(seals MessageSet) (types.IstanbulEpochValidatorSetSeal, error) { + epochSeals := make([][]byte, seals.Size()) + for i, v := range seals.Values() { + epochSeals[i] = make([]byte, types.IstanbulExtraBlsSignature) + + var commit *istanbul.CommittedSubject + err := v.Decode(&commit) + if err != nil { + return types.IstanbulEpochValidatorSetSeal{}, err + } + copy(epochSeals[i], commit.EpochValidatorSetSeal[:]) + } + + asig, err := blscrypto.AggregateSignatures(epochSeals) + if err != nil { + return types.IstanbulEpochValidatorSetSeal{}, err + } + return types.IstanbulEpochValidatorSetSeal{Signature: asig}, nil +} + // Generates the next preprepare request and associated round change certificate func (c *core) getPreprepareWithRoundChangeCertificate(round *big.Int) (*istanbul.Request, istanbul.RoundChangeCertificate, error) { logger := c.newLogger("func", "getPreprepareWithRoundChangeCertificate", "for_round", round) diff --git a/consensus/istanbul/core/core_test.go b/consensus/istanbul/core/core_test.go index e7b9ee0c216e..5792fdb7bbff 100644 --- a/consensus/istanbul/core/core_test.go +++ b/consensus/istanbul/core/core_test.go @@ -50,6 +50,7 @@ func makeBlockWithDifficulty(number, difficulty int64) *types.Block { } block := &types.Block{} block = block.WithRandomness(&types.EmptyRandomness) + block = block.WithEpochSnarkData(&types.EmptyEpochSnarkData) return block.WithSeal(header) } diff --git a/consensus/istanbul/core/errors.go b/consensus/istanbul/core/errors.go index 71fe05ec057f..4e67cdebac43 100644 --- a/consensus/istanbul/core/errors.go +++ b/consensus/istanbul/core/errors.go @@ -71,6 +71,10 @@ var ( // errInvalidCommittedSeal is returned when a COMMIT message has an invalid committed seal. errInvalidCommittedSeal = errors.New("invalid committed seal in COMMIT message") + // errInvalidEpochValidatorSetSeal is returned when a COMMIT message has an invalid epoch validator seal. + errInvalidEpochValidatorSetSeal = errors.New("invalid epoch validator set seal in COMMIT message") + // errNotLastBlockInEpoch is returned when the block number was not the last block in the epoch + errNotLastBlockInEpoch = errors.New("not last block in epoch") // errMissingRoundChangeCertificate is returned when ROUND CHANGE certificate is missing from a PREPREPARE for round > 0. errMissingRoundChangeCertificate = errors.New("missing ROUND CHANGE certificate in PREPREPARE") // errFailedCreateRoundChangeCertificate is returned when there aren't enough ROUND CHANGE messages to create a ROUND CHANGE certificate. diff --git a/consensus/istanbul/core/prepare.go b/consensus/istanbul/core/prepare.go index 54b4430928fa..798b632bca99 100644 --- a/consensus/istanbul/core/prepare.go +++ b/consensus/istanbul/core/prepare.go @@ -100,6 +100,16 @@ func (c *core) verifyPreparedCertificate(preparedCertificate istanbul.PreparedCe return nil, err } + newValSet, err := c.backend.NextBlockValidators(preparedCertificate.Proposal) + if err != nil { + return nil, err + } + err = c.verifyEpochValidatorSetSeal(committedSubject, preparedCertificate.Proposal.Number().Uint64(), newValSet, src) + if err != nil { + logger.Error("Epoch validator set seal seal did not contain signature from message signer.", "err", err) + return nil, err + } + subject = committedSubject.Subject } else { if err := message.Decode(&subject); err != nil { diff --git a/consensus/istanbul/core/roundstate_db_test.go b/consensus/istanbul/core/roundstate_db_test.go index d4dbeb6c8478..8c6b535a96d0 100644 --- a/consensus/istanbul/core/roundstate_db_test.go +++ b/consensus/istanbul/core/roundstate_db_test.go @@ -3,6 +3,7 @@ package core import ( "bytes" "encoding/hex" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "math/rand" "testing" @@ -12,10 +13,12 @@ import ( ) func TestRSDBRoundStateDB(t *testing.T) { + pubkey1 := blscrypto.SerializedPublicKey{1, 2, 3} + pubkey2 := blscrypto.SerializedPublicKey{3, 1, 4} dummyRoundState := func() RoundState { valSet := validator.NewSet([]istanbul.ValidatorData{ - {Address: common.BytesToAddress([]byte(string(2))), BLSPublicKey: []byte{1, 2, 3}}, - {Address: common.BytesToAddress([]byte(string(4))), BLSPublicKey: []byte{3, 1, 4}}, + {Address: common.BytesToAddress([]byte(string(2))), BLSPublicKey: pubkey1}, + {Address: common.BytesToAddress([]byte(string(4))), BLSPublicKey: pubkey2}, }) return newRoundState(newView(2, 1), valSet, valSet.GetByIndex(0)) } @@ -52,10 +55,12 @@ func TestRSDBRoundStateDB(t *testing.T) { } func TestRSDBDeleteEntriesOlderThan(t *testing.T) { + pubkey1 := blscrypto.SerializedPublicKey{1, 2, 3} + pubkey2 := blscrypto.SerializedPublicKey{3, 1, 4} createRoundState := func(view *istanbul.View) RoundState { valSet := validator.NewSet([]istanbul.ValidatorData{ - {Address: common.BytesToAddress([]byte(string(2))), BLSPublicKey: []byte{1, 2, 3}}, - {Address: common.BytesToAddress([]byte(string(4))), BLSPublicKey: []byte{3, 1, 4}}, + {Address: common.BytesToAddress([]byte(string(2))), BLSPublicKey: pubkey1}, + {Address: common.BytesToAddress([]byte(string(4))), BLSPublicKey: pubkey2}, }) return newRoundState(view, valSet, valSet.GetByIndex(0)) } @@ -125,9 +130,11 @@ func TestRSDBKeyEncodingOrder(t *testing.T) { } func TestRSDBGetOldestValidView(t *testing.T) { + pubkey1 := blscrypto.SerializedPublicKey{1, 2, 3} + pubkey2 := blscrypto.SerializedPublicKey{3, 1, 4} valSet := validator.NewSet([]istanbul.ValidatorData{ - {Address: common.BytesToAddress([]byte(string(2))), BLSPublicKey: []byte{1, 2, 3}}, - {Address: common.BytesToAddress([]byte(string(4))), BLSPublicKey: []byte{3, 1, 4}}, + {Address: common.BytesToAddress([]byte(string(2))), BLSPublicKey: pubkey1}, + {Address: common.BytesToAddress([]byte(string(4))), BLSPublicKey: pubkey2}, }) sequencesToSave := uint64(100) runTestCase := func(name string, viewToStore, expectedView *istanbul.View) { diff --git a/consensus/istanbul/core/roundstate_test.go b/consensus/istanbul/core/roundstate_test.go index 3361ff0ec533..ccb2cc90b322 100644 --- a/consensus/istanbul/core/roundstate_test.go +++ b/consensus/istanbul/core/roundstate_test.go @@ -2,6 +2,7 @@ package core import ( "encoding/json" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "math/big" "reflect" "sort" @@ -17,8 +18,8 @@ import ( func TestRoundStateRLPEncoding(t *testing.T) { dummyRoundState := func() RoundState { valSet := validator.NewSet([]istanbul.ValidatorData{ - {Address: common.HexToAddress("2"), BLSPublicKey: []byte{1, 2, 3}}, - {Address: common.HexToAddress("4"), BLSPublicKey: []byte{3, 1, 4}}, + {Address: common.HexToAddress("2"), BLSPublicKey: blscrypto.SerializedPublicKey{1, 2, 3}}, + {Address: common.HexToAddress("4"), BLSPublicKey: blscrypto.SerializedPublicKey{3, 1, 4}}, }) view := &istanbul.View{Round: big.NewInt(1), Sequence: big.NewInt(2)} return newRoundState(view, valSet, valSet.GetByIndex(0)) @@ -99,7 +100,7 @@ func TestRoundStateSummary(t *testing.T) { valData := make([]istanbul.ValidatorData, len(validatorAddresses)) for i, addr := range validatorAddresses { - valData[i] = istanbul.ValidatorData{Address: addr, BLSPublicKey: []byte{1, 2, 3}} + valData[i] = istanbul.ValidatorData{Address: addr, BLSPublicKey: blscrypto.SerializedPublicKey{1, 2, 3}} } valSet := validator.NewSet(valData) diff --git a/consensus/istanbul/core/testbackend_test.go b/consensus/istanbul/core/testbackend_test.go index 065352d6da28..381d193312b9 100644 --- a/consensus/istanbul/core/testbackend_test.go +++ b/consensus/istanbul/core/testbackend_test.go @@ -62,15 +62,16 @@ type testSystemBackend struct { } type testCommittedMsgs struct { - commitProposal istanbul.Proposal - aggregatedSeal types.IstanbulAggregatedSeal + commitProposal istanbul.Proposal + aggregatedSeal types.IstanbulAggregatedSeal + aggregatedEpochValidatorSetSeal types.IstanbulEpochValidatorSetSeal } // ============================================== // // define the functions that needs to be provided for Istanbul. -func (self *testSystemBackend) Authorize(address common.Address, _ istanbul.SignerFn, _ istanbul.SignerFn, _ istanbul.MessageSignerFn) { +func (self *testSystemBackend) Authorize(address common.Address, _ istanbul.SignerFn, _ istanbul.BLSSignerFn, _ istanbul.MessageSignerFn) { self.address = address self.engine.SetAddress(address) } @@ -84,6 +85,11 @@ func (self *testSystemBackend) Validators(proposal istanbul.Proposal) istanbul.V return self.peers } +func (self *testSystemBackend) NextBlockValidators(proposal istanbul.Proposal) (istanbul.ValidatorSet, error) { + //This doesn't really return the next block validators + return self.peers, nil +} + func (self *testSystemBackend) EventMux() *event.TypeMux { return self.events } @@ -110,7 +116,7 @@ func (self *testSystemBackend) Gossip(validators []common.Address, message []byt return nil } -func (self *testSystemBackend) SignBlockHeader(data []byte) ([]byte, error) { +func (self *testSystemBackend) SignBlockHeader(data []byte) (blscrypto.SerializedSignature, error) { privateKey, _ := bls.DeserializePrivateKey(self.blsKey) defer privateKey.Destroy() @@ -118,14 +124,26 @@ func (self *testSystemBackend) SignBlockHeader(data []byte) ([]byte, error) { defer signature.Destroy() signatureBytes, _ := signature.Serialize() - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) +} + +func (self *testSystemBackend) SignBLSWithCompositeHash(data []byte) (blscrypto.SerializedSignature, error) { + privateKey, _ := bls.DeserializePrivateKey(self.blsKey) + defer privateKey.Destroy() + + signature, _ := privateKey.SignMessage(data, []byte{}, true) + defer signature.Destroy() + signatureBytes, _ := signature.Serialize() + + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } -func (self *testSystemBackend) Commit(proposal istanbul.Proposal, aggregatedSeal types.IstanbulAggregatedSeal) error { +func (self *testSystemBackend) Commit(proposal istanbul.Proposal, aggregatedSeal types.IstanbulAggregatedSeal, aggregatedEpochValidatorSetSeal types.IstanbulEpochValidatorSetSeal) error { testLogger.Info("commit message", "address", self.Address()) self.committedMsgs = append(self.committedMsgs, testCommittedMsgs{ - commitProposal: proposal, - aggregatedSeal: aggregatedSeal, + commitProposal: proposal, + aggregatedSeal: aggregatedSeal, + aggregatedEpochValidatorSetSeal: aggregatedEpochValidatorSetSeal, }) // fake new head events @@ -255,7 +273,7 @@ func (self *testSystemBackend) getCommitMessage(view istanbul.View, proposal ist committedSubject := &istanbul.CommittedSubject{ Subject: subject, - CommittedSeal: committedSeal, + CommittedSeal: committedSeal[:], } payload, err := Encode(committedSubject) diff --git a/consensus/istanbul/types.go b/consensus/istanbul/types.go index 9614dc18fc01..a23402a9d00b 100644 --- a/consensus/istanbul/types.go +++ b/consensus/istanbul/types.go @@ -217,6 +217,7 @@ func EmptyPreparedCertificate() PreparedCertificate { } block := &types.Block{} block = block.WithRandomness(&types.EmptyRandomness) + block = block.WithEpochSnarkData(&types.EmptyEpochSnarkData) return PreparedCertificate{ Proposal: block.WithSeal(emptyHeader), @@ -314,8 +315,9 @@ func (s *Subject) String() string { // ## CommittedSubject ################################################################# type CommittedSubject struct { - Subject *Subject - CommittedSeal []byte + Subject *Subject + CommittedSeal []byte + EpochValidatorSetSeal []byte } // ## ForwardMessage ################################################################# diff --git a/consensus/istanbul/types_test.go b/consensus/istanbul/types_test.go index 329a1162cc6d..1709c721a86e 100644 --- a/consensus/istanbul/types_test.go +++ b/consensus/istanbul/types_test.go @@ -268,8 +268,9 @@ func TestSubjectRLPEncoding(t *testing.T) { func TestCommittedSubjectRLPEncoding(t *testing.T) { var result, original *CommittedSubject original = &CommittedSubject{ - Subject: dummySubject(), - CommittedSeal: []byte{12, 13, 23}, + Subject: dummySubject(), + CommittedSeal: []byte{12, 13, 23}, + EpochValidatorSetSeal: []byte{1, 5, 50}, } rawVal, err := rlp.EncodeToBytes(original) diff --git a/consensus/istanbul/utils.go b/consensus/istanbul/utils.go index d4f535d8ac73..235b0bec3340 100644 --- a/consensus/istanbul/utils.go +++ b/consensus/istanbul/utils.go @@ -17,9 +17,9 @@ package istanbul import ( - "bytes" "encoding/hex" "errors" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "math/big" "github.com/ethereum/go-ethereum/common" @@ -147,7 +147,7 @@ func ValidatorSetDiff(oldValSet []ValidatorData, newValSet []ValidatorData) ([]V var addedValidators []ValidatorData for _, newVal := range newValSet { index, ok := oldValSetIndices[newVal.Address] - if ok && bytes.Equal(oldValSet[index].BLSPublicKey, newVal.BLSPublicKey) { + if ok && (oldValSet[index].BLSPublicKey == newVal.BLSPublicKey) { // We found a common validator. Pop from the map delete(valSetMap, newVal.Address) } else { @@ -182,13 +182,13 @@ func CompareValidatorSlices(valSet1 []common.Address, valSet2 []common.Address) return true } -func CompareValidatorPublicKeySlices(valSet1 [][]byte, valSet2 [][]byte) bool { +func CompareValidatorPublicKeySlices(valSet1 []blscrypto.SerializedPublicKey, valSet2 []blscrypto.SerializedPublicKey) bool { if len(valSet1) != len(valSet2) { return false } for i := 0; i < len(valSet1); i++ { - if !bytes.Equal(valSet1[i], valSet2[i]) { + if valSet1[i] != valSet2[i] { return false } } @@ -196,10 +196,10 @@ func CompareValidatorPublicKeySlices(valSet1 [][]byte, valSet2 [][]byte) bool { return true } -func ConvertPublicKeysToStringSlice(publicKeys [][]byte) []string { +func ConvertPublicKeysToStringSlice(publicKeys []blscrypto.SerializedPublicKey) []string { publicKeyStrs := []string{} for i := 0; i < len(publicKeys); i++ { - publicKeyStrs = append(publicKeyStrs, hex.EncodeToString(publicKeys[i])) + publicKeyStrs = append(publicKeyStrs, hex.EncodeToString(publicKeys[i][:])) } return publicKeyStrs diff --git a/consensus/istanbul/utils_test.go b/consensus/istanbul/utils_test.go index 6561f719eef3..c24f38e3edb2 100644 --- a/consensus/istanbul/utils_test.go +++ b/consensus/istanbul/utils_test.go @@ -17,6 +17,7 @@ package istanbul import ( + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "math/big" "testing" @@ -112,14 +113,14 @@ func TestValSetDiff(t *testing.T) { for _, addr := range tt.inputOldValset { convertedInputOldValSet = append(convertedInputOldValSet, ValidatorData{ addr, - []byte{}, + blscrypto.SerializedPublicKey{}, }) } convertedInputNewValSet := []ValidatorData{} for _, addr := range tt.inputNewValset { convertedInputNewValSet = append(convertedInputNewValSet, ValidatorData{ addr, - []byte{}, + blscrypto.SerializedPublicKey{}, }) } addedVals, removedVals := ValidatorSetDiff(convertedInputOldValSet, convertedInputNewValSet) diff --git a/consensus/istanbul/validator.go b/consensus/istanbul/validator.go index 21662e8aecc9..d355b41f5a8d 100644 --- a/consensus/istanbul/validator.go +++ b/consensus/istanbul/validator.go @@ -20,6 +20,7 @@ import ( "bytes" "errors" "fmt" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "math/big" "github.com/ethereum/go-ethereum/common" @@ -31,7 +32,7 @@ var ( type ValidatorData struct { Address common.Address - BLSPublicKey []byte + BLSPublicKey blscrypto.SerializedPublicKey } type Validator interface { @@ -40,7 +41,7 @@ type Validator interface { // Address returns address Address() common.Address - BLSPublicKey() []byte + BLSPublicKey() blscrypto.SerializedPublicKey // Serialize returns binary reprenstation of the Validator // can be use used to instantiate a validator with DeserializeValidator() @@ -122,7 +123,7 @@ type ProposerSelector func(validatorSet ValidatorSet, lastBlockProposer common.A // ---------------------------------------------------------------------------- -func CombineIstanbulExtraToValidatorData(addrs []common.Address, blsPublicKeys [][]byte) ([]ValidatorData, error) { +func CombineIstanbulExtraToValidatorData(addrs []common.Address, blsPublicKeys []blscrypto.SerializedPublicKey) ([]ValidatorData, error) { if len(addrs) != len(blsPublicKeys) { return nil, errInvalidValidatorSetDiffSize } @@ -137,9 +138,9 @@ func CombineIstanbulExtraToValidatorData(addrs []common.Address, blsPublicKeys [ return validators, nil } -func SeparateValidatorDataIntoIstanbulExtra(validators []ValidatorData) ([]common.Address, [][]byte) { +func SeparateValidatorDataIntoIstanbulExtra(validators []ValidatorData) ([]common.Address, []blscrypto.SerializedPublicKey) { addrs := []common.Address{} - pubKeys := [][]byte{} + pubKeys := []blscrypto.SerializedPublicKey{} for i := range validators { addrs = append(addrs, validators[i].Address) pubKeys = append(pubKeys, validators[i].BLSPublicKey) diff --git a/consensus/istanbul/validator/default.go b/consensus/istanbul/validator/default.go index 9ff2e995beb2..e25baca653eb 100644 --- a/consensus/istanbul/validator/default.go +++ b/consensus/istanbul/validator/default.go @@ -25,12 +25,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/istanbul" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "github.com/ethereum/go-ethereum/rlp" ) type defaultValidator struct { address common.Address - blsPublicKey []byte + blsPublicKey blscrypto.SerializedPublicKey } func newValidatorFromData(data *istanbul.ValidatorData) *defaultValidator { @@ -47,9 +48,9 @@ func (val *defaultValidator) AsData() *istanbul.ValidatorData { } } -func (val *defaultValidator) Address() common.Address { return val.address } -func (val *defaultValidator) BLSPublicKey() []byte { return val.blsPublicKey } -func (val *defaultValidator) String() string { return val.Address().String() } +func (val *defaultValidator) Address() common.Address { return val.address } +func (val *defaultValidator) BLSPublicKey() blscrypto.SerializedPublicKey { return val.blsPublicKey } +func (val *defaultValidator) String() string { return val.Address().String() } func (val *defaultValidator) Serialize() ([]byte, error) { return rlp.EncodeToBytes(val) } diff --git a/consensus/istanbul/validator/default_test.go b/consensus/istanbul/validator/default_test.go index 388322e46e22..b4aa9c6c15c0 100644 --- a/consensus/istanbul/validator/default_test.go +++ b/consensus/istanbul/validator/default_test.go @@ -56,7 +56,7 @@ func testNewValidatorSet(t *testing.T) { val := New(addr, blsPublicKey) validators = append(validators, val) b = append(b, val.Address().Bytes()...) - b = append(b, blsPublicKey...) + b = append(b, blsPublicKey[:]...) } // Create ValidatorSet @@ -72,10 +72,10 @@ func testNormalValSet(t *testing.T) { b2 := common.Hex2Bytes(testAddress2) addr1 := common.BytesToAddress(b1) addr2 := common.BytesToAddress(b2) - val1 := New(addr1, []byte{}) - val2 := New(addr2, []byte{}) + val1 := New(addr1, blscrypto.SerializedPublicKey{}) + val2 := New(addr2, blscrypto.SerializedPublicKey{}) - validators, _ := istanbul.CombineIstanbulExtraToValidatorData([]common.Address{addr1, addr2}, [][]byte{{}, {}}) + validators, _ := istanbul.CombineIstanbulExtraToValidatorData([]common.Address{addr1, addr2}, []blscrypto.SerializedPublicKey{{}, {}}) valSet := newDefaultSet(validators) if valSet == nil { t.Errorf("the format of validator set is invalid") @@ -118,7 +118,7 @@ func testAddAndRemoveValidator(t *testing.T) { []istanbul.ValidatorData{ { common.BytesToAddress([]byte(string(3))), - []byte{}, + blscrypto.SerializedPublicKey{}, }, }, ) { @@ -128,7 +128,7 @@ func testAddAndRemoveValidator(t *testing.T) { []istanbul.ValidatorData{ { common.BytesToAddress([]byte(string(3))), - []byte{}, + blscrypto.SerializedPublicKey{}, }, }, ) { @@ -138,11 +138,11 @@ func testAddAndRemoveValidator(t *testing.T) { []istanbul.ValidatorData{ { common.BytesToAddress([]byte(string(2))), - []byte{}, + blscrypto.SerializedPublicKey{}, }, { common.BytesToAddress([]byte(string(1))), - []byte{}, + blscrypto.SerializedPublicKey{}, }, }, ) @@ -217,7 +217,7 @@ func testQuorumSizes(t *testing.T) { func TestValidatorRLPEncoding(t *testing.T) { - val := New(common.BytesToAddress([]byte(string(2))), []byte{1, 2, 3}) + val := New(common.BytesToAddress([]byte(string(2))), blscrypto.SerializedPublicKey{1, 2, 3}) rawVal, err := rlp.EncodeToBytes(val) if err != nil { @@ -237,8 +237,8 @@ func TestValidatorRLPEncoding(t *testing.T) { func TestValidatorSetRLPEncoding(t *testing.T) { valSet := NewSet([]istanbul.ValidatorData{ - {Address: common.BytesToAddress([]byte(string(2))), BLSPublicKey: []byte{1, 2, 3}}, - {Address: common.BytesToAddress([]byte(string(4))), BLSPublicKey: []byte{3, 1, 4}}, + {Address: common.BytesToAddress([]byte(string(2))), BLSPublicKey: blscrypto.SerializedPublicKey{1, 2, 3}}, + {Address: common.BytesToAddress([]byte(string(4))), BLSPublicKey: blscrypto.SerializedPublicKey{3, 1, 4}}, }) rawVal, err := rlp.EncodeToBytes(valSet) diff --git a/consensus/istanbul/validator/selectors_test.go b/consensus/istanbul/validator/selectors_test.go index 0b703c6d9828..a0af3dfe958f 100644 --- a/consensus/istanbul/validator/selectors_test.go +++ b/consensus/istanbul/validator/selectors_test.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/istanbul" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" ) var testAddresses = []string{ @@ -39,10 +40,10 @@ func TestStickyProposer(t *testing.T) { for _, strAddr := range testAddresses { addr := common.HexToAddress(strAddr) addrs = append(addrs, addr) - validators = append(validators, New(addr, nil)) + validators = append(validators, New(addr, blscrypto.SerializedPublicKey{})) } - v, err := istanbul.CombineIstanbulExtraToValidatorData(addrs, make([][]byte, len(addrs))) + v, err := istanbul.CombineIstanbulExtraToValidatorData(addrs, make([]blscrypto.SerializedPublicKey, len(addrs))) if err != nil { t.Fatalf("CombineIstanbulExtraToValidatorData(...): %v", err) } @@ -96,10 +97,10 @@ func TestRoundRobinProposer(t *testing.T) { for _, strAddr := range testAddresses { addr := common.HexToAddress(strAddr) addrs = append(addrs, addr) - validators = append(validators, New(addr, nil)) + validators = append(validators, New(addr, blscrypto.SerializedPublicKey{})) } - v, err := istanbul.CombineIstanbulExtraToValidatorData(addrs, make([][]byte, len(addrs))) + v, err := istanbul.CombineIstanbulExtraToValidatorData(addrs, make([]blscrypto.SerializedPublicKey, len(addrs))) if err != nil { t.Fatalf("CombineIstanbulExtraToValidatorData(...): %v", err) } @@ -153,10 +154,10 @@ func TestShuffledRoundRobinProposer(t *testing.T) { for _, strAddr := range testAddresses { addr := common.HexToAddress(strAddr) addrs = append(addrs, addr) - validators = append(validators, New(addr, nil)) + validators = append(validators, New(addr, blscrypto.SerializedPublicKey{})) } - v, err := istanbul.CombineIstanbulExtraToValidatorData(addrs, make([][]byte, len(addrs))) + v, err := istanbul.CombineIstanbulExtraToValidatorData(addrs, make([]blscrypto.SerializedPublicKey, len(addrs))) if err != nil { t.Fatalf("CombineIstanbulExtraToValidatorData(...): %v", err) } diff --git a/consensus/istanbul/validator/validator.go b/consensus/istanbul/validator/validator.go index 10e90f296da7..ca1ff75d2bb3 100644 --- a/consensus/istanbul/validator/validator.go +++ b/consensus/istanbul/validator/validator.go @@ -23,7 +23,7 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) -func New(addr common.Address, blsPublicKey []byte) istanbul.Validator { +func New(addr common.Address, blsPublicKey blscrypto.SerializedPublicKey) istanbul.Validator { return &defaultValidator{ address: addr, blsPublicKey: blsPublicKey, diff --git a/contract_comm/validators/validators.go b/contract_comm/validators/validators.go index eea1625e4302..f93603bcc335 100644 --- a/contract_comm/validators/validators.go +++ b/contract_comm/validators/validators.go @@ -237,13 +237,17 @@ func GetValidatorData(header *types.Header, state vm.StateDB, validatorAddresses if err != nil { return nil, err } + if len(blsKey) != blscrypto.PUBLICKEYBYTES { - return nil, fmt.Errorf("length of BLS key incorrect. Expected %d, got %d", blscrypto.PUBLICKEYBYTES, len(blsKey)) + return nil, fmt.Errorf("length of bls public key incorrect. Expected %d, got %d", blscrypto.PUBLICKEYBYTES, len(blsKey)) } - validatorData = append(validatorData, istanbul.ValidatorData{ + blsKeyFixedSize := blscrypto.SerializedPublicKey{} + copy(blsKeyFixedSize[:], blsKey) + validator := istanbul.ValidatorData{ addr, - blsKey, - }) + blsKeyFixedSize, + } + validatorData = append(validatorData, validator) } return validatorData, nil } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 07a3af463b44..09302987707b 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -373,7 +373,7 @@ func ReadBlock(db DatabaseReader, hash common.Hash, number uint64) *types.Block if body == nil { return nil } - return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles, body.Randomness) + return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles, body.Randomness, body.EpochSnarkData) } // WriteBlock serializes a block into the database, header and body separately. diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 8cc4afb36170..8fa153a8e061 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -68,7 +68,7 @@ func TestBodyStorage(t *testing.T) { db := ethdb.NewMemDatabase() // Create a test body to move around the database and make sure it's really new - body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}, Randomness: &types.Randomness{}} + body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}, Randomness: &types.Randomness{}, EpochSnarkData: &types.EpochSnarkData{}} hasher := sha3.NewLegacyKeccak256() rlp.Encode(hasher, body) diff --git a/core/types/block.go b/core/types/block.go index 7067e0f73639..6f381793bcb5 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -28,14 +28,16 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto/bls" "github.com/ethereum/go-ethereum/rlp" "golang.org/x/crypto/sha3" ) var ( - EmptyRootHash = DeriveSha(Transactions{}) - EmptyUncleHash = CalcUncleHash(nil) - EmptyRandomness = Randomness{} + EmptyRootHash = DeriveSha(Transactions{}) + EmptyUncleHash = CalcUncleHash(nil) + EmptyRandomness = Randomness{} + EmptyEpochSnarkData = EpochSnarkData{} ) // A BlockNonce is a 64-bit hash which proves (combined with the @@ -149,20 +151,45 @@ func (r *Randomness) EncodeRLP(w io.Writer) error { return rlp.Encode(w, []interface{}{r.Revealed, r.Committed}) } +type EpochSnarkData struct { + Signature []byte +} + +func (r *EpochSnarkData) Size() common.StorageSize { + return common.StorageSize(blscrypto.SIGNATUREBYTES) +} + +func (r *EpochSnarkData) DecodeRLP(s *rlp.Stream) error { + var epochSnarkData struct { + Signature []byte + } + if err := s.Decode(&epochSnarkData); err != nil { + return err + } + r.Signature = epochSnarkData.Signature + return nil +} + +func (r *EpochSnarkData) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, []interface{}{r.Signature}) +} + // Body is a simple (mutable, non-safe) data container for storing and moving // a block's data contents (transactions and uncles) together. type Body struct { - Transactions []*Transaction - Uncles []*Header - Randomness *Randomness + Transactions []*Transaction + Uncles []*Header + Randomness *Randomness + EpochSnarkData *EpochSnarkData } // Block represents an entire block in the Ethereum blockchain. type Block struct { - header *Header - uncles []*Header - transactions Transactions - randomness *Randomness + header *Header + uncles []*Header + transactions Transactions + randomness *Randomness + epochSnarkData *EpochSnarkData // caches hash atomic.Value @@ -193,20 +220,22 @@ type StorageBlock Block // "external" block encoding. used for eth protocol, etc. type extblock struct { - Header *Header - Txs []*Transaction - Uncles []*Header - Randomness *Randomness + Header *Header + Txs []*Transaction + Uncles []*Header + Randomness *Randomness + EpochSnarkData *EpochSnarkData } // [deprecated by eth/63] // "storage" block encoding. used for database. type storageblock struct { - Header *Header - Txs []*Transaction - Uncles []*Header - Randomness *Randomness - TD *big.Int + Header *Header + Txs []*Transaction + Uncles []*Header + Randomness *Randomness + EpochSnarkData *EpochSnarkData + TD *big.Int } // NewBlock creates a new block. The input data is copied, @@ -217,7 +246,7 @@ type storageblock struct { // are ignored and set to values derived from the given txs, uncles // and receipts. func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, randomness *Randomness) *Block { - b := &Block{header: CopyHeader(header), td: new(big.Int), randomness: randomness} + b := &Block{header: CopyHeader(header), td: new(big.Int), randomness: randomness, epochSnarkData: &EmptyEpochSnarkData} // TODO: panic if len(txs) != len(receipts) if len(txs) == 0 { @@ -256,7 +285,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []* // header data is copied, changes to header and to the field values // will not affect the block. func NewBlockWithHeader(header *Header) *Block { - return &Block{header: CopyHeader(header), randomness: &EmptyRandomness} + return &Block{header: CopyHeader(header), randomness: &EmptyRandomness, epochSnarkData: &EmptyEpochSnarkData} } // CopyHeader creates a deep copy of a block header to prevent side effects from @@ -286,7 +315,7 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error { if err := s.Decode(&eb); err != nil { return err } - b.header, b.uncles, b.transactions, b.randomness = eb.Header, eb.Uncles, eb.Txs, eb.Randomness + b.header, b.uncles, b.transactions, b.randomness, b.epochSnarkData = eb.Header, eb.Uncles, eb.Txs, eb.Randomness, eb.EpochSnarkData b.size.Store(common.StorageSize(rlp.ListSize(size))) return nil } @@ -294,10 +323,11 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error { // EncodeRLP serializes b into the Ethereum RLP block format. func (b *Block) EncodeRLP(w io.Writer) error { return rlp.Encode(w, extblock{ - Header: b.header, - Txs: b.transactions, - Uncles: b.uncles, - Randomness: b.randomness, + Header: b.header, + Txs: b.transactions, + Uncles: b.uncles, + Randomness: b.randomness, + EpochSnarkData: b.epochSnarkData, }) } @@ -307,15 +337,16 @@ func (b *StorageBlock) DecodeRLP(s *rlp.Stream) error { if err := s.Decode(&sb); err != nil { return err } - b.header, b.uncles, b.transactions, b.td, b.randomness = sb.Header, sb.Uncles, sb.Txs, sb.TD, sb.Randomness + b.header, b.uncles, b.transactions, b.td, b.randomness, b.epochSnarkData = sb.Header, sb.Uncles, sb.Txs, sb.TD, sb.Randomness, sb.EpochSnarkData return nil } // TODO: copies -func (b *Block) Uncles() []*Header { return b.uncles } -func (b *Block) Transactions() Transactions { return b.transactions } -func (b *Block) Randomness() *Randomness { return b.randomness } +func (b *Block) Uncles() []*Header { return b.uncles } +func (b *Block) Transactions() Transactions { return b.transactions } +func (b *Block) Randomness() *Randomness { return b.randomness } +func (b *Block) EpochSnarkData() *EpochSnarkData { return b.epochSnarkData } func (b *Block) Transaction(hash common.Hash) *Transaction { for _, transaction := range b.transactions { @@ -348,7 +379,7 @@ func (b *Block) Header() *Header { return CopyHeader(b.header) } func (b *Block) MutableHeader() *Header { return b.header } // Body returns the non-header content of the block. -func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles, b.randomness} } +func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles, b.randomness, b.epochSnarkData} } // Size returns the true RLP encoded storage size of the block, either by encoding // and returning it, or returning a previsouly cached value. @@ -379,31 +410,46 @@ func (b *Block) WithSeal(header *Header) *Block { cpy := *header return &Block{ - header: &cpy, - transactions: b.transactions, - uncles: b.uncles, - randomness: b.randomness, + header: &cpy, + transactions: b.transactions, + uncles: b.uncles, + randomness: b.randomness, + epochSnarkData: b.epochSnarkData, } } // WithRandomness returns a new block with the given randomness. func (b *Block) WithRandomness(randomness *Randomness) *Block { block := &Block{ - header: b.header, - transactions: b.transactions, - uncles: b.uncles, - randomness: randomness, + header: b.header, + transactions: b.transactions, + uncles: b.uncles, + randomness: randomness, + epochSnarkData: b.epochSnarkData, + } + return block +} + +// WithEpochSnarkData returns a new block with the given epoch SNARK data. +func (b *Block) WithEpochSnarkData(epochSnarkData *EpochSnarkData) *Block { + block := &Block{ + header: b.header, + transactions: b.transactions, + uncles: b.uncles, + randomness: b.randomness, + epochSnarkData: epochSnarkData, } return block } // WithBody returns a new block with the given transaction and uncle contents. -func (b *Block) WithBody(transactions []*Transaction, uncles []*Header, randomness *Randomness) *Block { +func (b *Block) WithBody(transactions []*Transaction, uncles []*Header, randomness *Randomness, epochSnarkData *EpochSnarkData) *Block { block := &Block{ - header: CopyHeader(b.header), - transactions: make([]*Transaction, len(transactions)), - uncles: make([]*Header, len(uncles)), - randomness: randomness, + header: CopyHeader(b.header), + transactions: make([]*Transaction, len(transactions)), + uncles: make([]*Header, len(uncles)), + randomness: randomness, + epochSnarkData: epochSnarkData, } copy(block.transactions, transactions) for i := range uncles { @@ -412,6 +458,9 @@ func (b *Block) WithBody(transactions []*Transaction, uncles []*Header, randomne if randomness == nil { block.randomness = &EmptyRandomness } + if epochSnarkData == nil { + block.epochSnarkData = &EmptyEpochSnarkData + } return block } diff --git a/core/types/block_test.go b/core/types/block_test.go index 4a9ec0997df3..e2206962231c 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -28,7 +28,7 @@ import ( // from bcValidBlockTest.json, "SimpleTx" func TestBlockEncoding(t *testing.T) { - blockEnc := common.FromHex("f90265f901f9a07285abd5b24742f184ad676e31f6054663b3529bc35ea2fcad8a3e0f642a46f7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ecc60e00b3fe5ce9f6e1a10e5469764daf51f1fe93c22ec3f9a7583a80357217a0d35d334d87c0cc0a202e3756bf81fae08b1575f286c7ee7a3f8df4f0f3afc55da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845c47775c80a00000000000000000000000000000000000000000000000000000000000000000880000000000000000e3e2800a82c35080808094095e7baea6a6c7c4c2dfeb977efac326af552d870a80808080c0f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000") + blockEnc := common.FromHex("f90297f901f9a07285abd5b24742f184ad676e31f6054663b3529bc35ea2fcad8a3e0f642a46f7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ecc60e00b3fe5ce9f6e1a10e5469764daf51f1fe93c22ec3f9a7583a80357217a0d35d334d87c0cc0a202e3756bf81fae08b1575f286c7ee7a3f8df4f0f3afc55da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845c47775c80a00000000000000000000000000000000000000000000000000000000000000000880000000000000000e3e2800a82c35080808094095e7baea6a6c7c4c2dfeb977efac326af552d870a80808080c0f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000f1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") var block Block if err := rlp.DecodeBytes(blockEnc, &block); err != nil { t.Fatal("decode error: ", err) diff --git a/core/types/istanbul.go b/core/types/istanbul.go index 165fcbaef68f..438683e45652 100644 --- a/core/types/istanbul.go +++ b/core/types/istanbul.go @@ -50,6 +50,13 @@ type IstanbulAggregatedSeal struct { Round *big.Int } +type IstanbulEpochValidatorSetSeal struct { + // We don't add a bitmap here since it's assumed the same signers for the block have signed this + + // Signature is an aggregated BLS signature resulting from signatures by each validator that signed this block + Signature []byte +} + // EncodeRLP serializes ist into the Ethereum RLP format. func (ist *IstanbulAggregatedSeal) EncodeRLP(w io.Writer) error { return rlp.Encode(w, []interface{}{ @@ -81,7 +88,7 @@ type IstanbulExtra struct { // AddedValidators are the validators that have been added in the block AddedValidators []common.Address // AddedValidatorsPublicKeys are the BLS public keys for the validators added in the block - AddedValidatorsPublicKeys [][]byte + AddedValidatorsPublicKeys []blscrypto.SerializedPublicKey // RemovedValidators is a bitmap having an active bit for each removed validator in the block RemovedValidators *big.Int // Seal is an ECDSA signature by the proposer @@ -90,8 +97,6 @@ type IstanbulExtra struct { AggregatedSeal IstanbulAggregatedSeal // ParentAggregatedSeal contains and aggregated BLS signature for the previous block. ParentAggregatedSeal IstanbulAggregatedSeal - // EpochData is a SNARK-friendly encoding of the validator set diff (WIP) - EpochData []byte } // EncodeRLP serializes ist into the Ethereum RLP format. @@ -103,7 +108,6 @@ func (ist *IstanbulExtra) EncodeRLP(w io.Writer) error { ist.Seal, &ist.AggregatedSeal, &ist.ParentAggregatedSeal, - ist.EpochData, }) } @@ -111,17 +115,16 @@ func (ist *IstanbulExtra) EncodeRLP(w io.Writer) error { func (ist *IstanbulExtra) DecodeRLP(s *rlp.Stream) error { var istanbulExtra struct { AddedValidators []common.Address - AddedValidatorsPublicKeys [][]byte + AddedValidatorsPublicKeys []blscrypto.SerializedPublicKey RemovedValidators *big.Int Seal []byte AggregatedSeal IstanbulAggregatedSeal ParentAggregatedSeal IstanbulAggregatedSeal - EpochData []byte } if err := s.Decode(&istanbulExtra); err != nil { return err } - ist.AddedValidators, ist.AddedValidatorsPublicKeys, ist.RemovedValidators, ist.Seal, ist.AggregatedSeal, ist.ParentAggregatedSeal, ist.EpochData = istanbulExtra.AddedValidators, istanbulExtra.AddedValidatorsPublicKeys, istanbulExtra.RemovedValidators, istanbulExtra.Seal, istanbulExtra.AggregatedSeal, istanbulExtra.ParentAggregatedSeal, istanbulExtra.EpochData + ist.AddedValidators, ist.AddedValidatorsPublicKeys, ist.RemovedValidators, ist.Seal, ist.AggregatedSeal, ist.ParentAggregatedSeal = istanbulExtra.AddedValidators, istanbulExtra.AddedValidatorsPublicKeys, istanbulExtra.RemovedValidators, istanbulExtra.Seal, istanbulExtra.AggregatedSeal, istanbulExtra.ParentAggregatedSeal return nil } diff --git a/core/types/istanbul_test.go b/core/types/istanbul_test.go index a9dc8fd5e959..8a47732c257e 100644 --- a/core/types/istanbul_test.go +++ b/core/types/istanbul_test.go @@ -18,6 +18,7 @@ package types import ( "bytes" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "math/big" "reflect" "testing" @@ -55,18 +56,17 @@ func TestExtractToIstanbul(t *testing.T) { { // normal case bytes.Repeat([]byte{0x00}, IstanbulExtraVanity), - hexutil.MustDecode("0xf7ea9444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212c00c80c3808080c380808080"), + hexutil.MustDecode("0xf6ea9444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212c00c80c3808080c3808080"), &IstanbulExtra{ AddedValidators: []common.Address{ common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")), common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")), }, - AddedValidatorsPublicKeys: [][]byte{}, + AddedValidatorsPublicKeys: []blscrypto.SerializedPublicKey{}, RemovedValidators: big.NewInt(12), //1100 Seal: []byte{}, AggregatedSeal: IstanbulAggregatedSeal{big.NewInt(0), []byte{}, big.NewInt(0)}, ParentAggregatedSeal: IstanbulAggregatedSeal{big.NewInt(0), []byte{}, big.NewInt(0)}, - EpochData: []byte{}, }, nil, }, diff --git a/core/vm/contracts.go b/core/vm/contracts.go index c376a8a3238c..00a700acd6e8 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -578,8 +578,8 @@ func (c *proofOfPossession) Run(input []byte, caller common.Address, evm *EVM, g // input is comprised of 3 arguments: // address: 20 bytes, an address used to generate the proof-of-possession - // publicKey: 48 bytes, representing the public key (defined as a const in bls package) - // signature: 96 bytes, representing the signature on `address` (defined as a const in bls package) + // publicKey: 96 bytes, representing the public key (defined as a const in bls package) + // signature: 48 bytes, representing the signature on `address` (defined as a const in bls package) // the total length of input required is the sum of these constants if len(input) != common.AddressLength+blscrypto.PUBLICKEYBYTES+blscrypto.SIGNATUREBYTES { return nil, gas, ErrInputLength diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index 0ddccc95a504..57e8cffae84f 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -19,6 +19,7 @@ package vm import ( "errors" "fmt" + blscrypto "github.com/ethereum/go-ethereum/crypto/bls" "math/big" "testing" @@ -56,7 +57,7 @@ func (e mockEngine) GetValidators(number *big.Int, _ common.Hash) []istanbul.Val hash := sha3.Sum256(preimage) var validators []istanbul.Validator for i := 0; i < 16; i, hash = i+1, sha3.Sum256(hash[:]) { - validators = append(validators, validator.New(common.BytesToAddress(hash[:]), nil)) + validators = append(validators, validator.New(common.BytesToAddress(hash[:]), blscrypto.SerializedPublicKey{})) } return validators } diff --git a/crypto/bls/bls.go b/crypto/bls/bls.go index c76ed6688020..218142833719 100644 --- a/crypto/bls/bls.go +++ b/crypto/bls/bls.go @@ -12,11 +12,14 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) -var ( +const ( PUBLICKEYBYTES = bls.PUBLICKEYBYTES SIGNATUREBYTES = bls.SIGNATUREBYTES ) +type SerializedPublicKey [PUBLICKEYBYTES]byte +type SerializedSignature [SIGNATUREBYTES]byte + func ECDSAToBLS(privateKeyECDSA *ecdsa.PrivateKey) ([]byte, error) { for i := 0; i < 256; i++ { modulus := big.NewInt(0) @@ -70,31 +73,34 @@ func ECDSAToBLS(privateKeyECDSA *ecdsa.PrivateKey) ([]byte, error) { return nil, errors.New("couldn't derive a BLS key from an ECDSA key") } -func PrivateToPublic(privateKeyBytes []byte) ([]byte, error) { +func PrivateToPublic(privateKeyBytes []byte) (SerializedPublicKey, error) { privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return SerializedPublicKey{}, err } defer privateKey.Destroy() publicKey, err := privateKey.ToPublic() if err != nil { - return nil, err + return SerializedPublicKey{}, err } defer publicKey.Destroy() pubKeyBytes, err := publicKey.Serialize() if err != nil { - return nil, err + return SerializedPublicKey{}, err } - return pubKeyBytes, nil + pubKeyBytesFixed := SerializedPublicKey{} + copy(pubKeyBytesFixed[:], pubKeyBytes) + + return pubKeyBytesFixed, nil } -func VerifyAggregatedSignature(publicKeys [][]byte, message []byte, extraData []byte, signature []byte, shouldUseCompositeHasher bool) error { +func VerifyAggregatedSignature(publicKeys []SerializedPublicKey, message []byte, extraData []byte, signature []byte, shouldUseCompositeHasher bool) error { publicKeyObjs := []*bls.PublicKey{} for _, publicKey := range publicKeys { - publicKeyObj, err := bls.DeserializePublicKey(publicKey) + publicKeyObj, err := bls.DeserializePublicKey(publicKey[:]) if err != nil { return err } @@ -142,8 +148,8 @@ func AggregateSignatures(signatures [][]byte) ([]byte, error) { return asigBytes, nil } -func VerifySignature(publicKey []byte, message []byte, extraData []byte, signature []byte, shouldUseCompositeHasher bool) error { - publicKeyObj, err := bls.DeserializePublicKey(publicKey) +func VerifySignature(publicKey SerializedPublicKey, message []byte, extraData []byte, signature []byte, shouldUseCompositeHasher bool) error { + publicKeyObj, err := bls.DeserializePublicKey(publicKey[:]) if err != nil { return err } @@ -158,3 +164,32 @@ func VerifySignature(publicKey []byte, message []byte, extraData []byte, signatu err = publicKeyObj.VerifySignature(message, extraData, signatureObj, shouldUseCompositeHasher) return err } + +func EncodeEpochSnarkData(newValSet []SerializedPublicKey, maximumNonSignersPlusOne uint32, epochIndex uint16) ([]byte, error) { + pubKeys := []*bls.PublicKey{} + for _, pubKey := range newValSet { + publicKeyObj, err := bls.DeserializePublicKey(pubKey[:]) + if err != nil { + return nil, err + } + defer publicKeyObj.Destroy() + + pubKeys = append(pubKeys, publicKeyObj) + } + apk, err := bls.AggregatePublicKeys(pubKeys) + if err != nil { + return nil, err + } + defer apk.Destroy() + + return bls.EncodeEpochToBytes(epochIndex, maximumNonSignersPlusOne, apk, pubKeys) +} + +func SerializedSignatureFromBytes(serializedSignature []byte) (SerializedSignature, error) { + if len(serializedSignature) != SIGNATUREBYTES { + return SerializedSignature{}, fmt.Errorf("wrong length for serialized signature: expected %d, got %d", SIGNATUREBYTES, len(serializedSignature)) + } + signatureBytesFixed := SerializedSignature{} + copy(signatureBytesFixed[:], serializedSignature) + return signatureBytesFixed, nil +} diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index b0c6ba6f7872..dd13f740729d 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -1176,7 +1176,7 @@ func (d *Downloader) fetchBodies(from uint64) error { var ( deliver = func(packet dataPack) (int, error) { pack := packet.(*bodyPack) - return d.queue.DeliverBodies(pack.peerID, pack.transactions, pack.uncles, pack.randomness) + return d.queue.DeliverBodies(pack.peerID, pack.transactions, pack.uncles, pack.randomness, pack.epochSnarkData) } expire = func() map[string]int { return d.queue.ExpireBodies(d.requestTTL()) } fetch = func(p *peerConnection, req *fetchRequest) error { return p.FetchBodies(req) } @@ -1613,7 +1613,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error { ) blocks := make([]*types.Block, len(results)) for i, result := range results { - blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles, result.Randomness) + blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles, result.Randomness, result.EpochSnarkData) } if index, err := d.blockchain.InsertChain(blocks); err != nil { if index < len(results) { @@ -1763,7 +1763,7 @@ func (d *Downloader) commitFastSyncData(results []*fetchResult, stateSync *state blocks := make([]*types.Block, len(results)) receipts := make([]types.Receipts, len(results)) for i, result := range results { - blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles, result.Randomness) + blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles, result.Randomness, result.EpochSnarkData) receipts[i] = result.Receipts } if index, err := d.blockchain.InsertReceiptChain(blocks, receipts); err != nil { @@ -1774,7 +1774,7 @@ func (d *Downloader) commitFastSyncData(results []*fetchResult, stateSync *state } func (d *Downloader) commitPivotBlock(result *fetchResult) error { - block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles, result.Randomness) + block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles, result.Randomness, result.EpochSnarkData) log.Debug("Committing fast sync pivot as new head", "number", block.Number(), "hash", block.Hash()) if _, err := d.blockchain.InsertReceiptChain([]*types.Block{block}, []types.Receipts{result.Receipts}); err != nil { return err @@ -1793,8 +1793,8 @@ func (d *Downloader) DeliverHeaders(id string, headers []*types.Header) (err err } // DeliverBodies injects a new batch of block bodies received from a remote node. -func (d *Downloader) DeliverBodies(id string, transactions [][]*types.Transaction, uncles [][]*types.Header, randomness []*types.Randomness) (err error) { - return d.deliver(id, d.bodyCh, &bodyPack{id, transactions, uncles, randomness}, bodyInMeter, bodyDropMeter) +func (d *Downloader) DeliverBodies(id string, transactions [][]*types.Transaction, uncles [][]*types.Header, randomness []*types.Randomness, epochSnarkData []*types.EpochSnarkData) (err error) { + return d.deliver(id, d.bodyCh, &bodyPack{id, transactions, uncles, randomness, epochSnarkData}, bodyInMeter, bodyDropMeter) } // DeliverReceipts injects a new batch of receipts received from a remote node. diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 38783dbd7ba6..b54a5cb247d9 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -359,8 +359,8 @@ func (dlp *downloadTesterPeer) RequestHeadersByNumber(origin uint64, amount int, // peer in the download tester. The returned function can be used to retrieve // batches of block bodies from the particularly requested peer. func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash) error { - txs, uncles, randomness := dlp.chain.bodies(hashes) - go dlp.dl.downloader.DeliverBodies(dlp.id, txs, uncles, randomness) + txs, uncles, randomness, epochSnarkData := dlp.chain.bodies(hashes) + go dlp.dl.downloader.DeliverBodies(dlp.id, txs, uncles, randomness, epochSnarkData) return nil } @@ -684,7 +684,7 @@ func TestInactiveDownloader62(t *testing.T) { if err := tester.downloader.DeliverHeaders("bad peer", []*types.Header{}); err != errNoSyncActive { t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive) } - if err := tester.downloader.DeliverBodies("bad peer", [][]*types.Transaction{}, [][]*types.Header{}, []*types.Randomness{}); err != errNoSyncActive { + if err := tester.downloader.DeliverBodies("bad peer", [][]*types.Transaction{}, [][]*types.Header{}, []*types.Randomness{}, []*types.EpochSnarkData{}); err != errNoSyncActive { t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive) } } @@ -701,7 +701,7 @@ func TestInactiveDownloader63(t *testing.T) { if err := tester.downloader.DeliverHeaders("bad peer", []*types.Header{}); err != errNoSyncActive { t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive) } - if err := tester.downloader.DeliverBodies("bad peer", [][]*types.Transaction{}, [][]*types.Header{}, []*types.Randomness{}); err != errNoSyncActive { + if err := tester.downloader.DeliverBodies("bad peer", [][]*types.Transaction{}, [][]*types.Header{}, []*types.Randomness{}, []*types.EpochSnarkData{}); err != errNoSyncActive { t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive) } if err := tester.downloader.DeliverReceipts("bad peer", [][]*types.Receipt{}); err != errNoSyncActive { diff --git a/eth/downloader/fakepeer.go b/eth/downloader/fakepeer.go index a87cf6a343a8..085be555910f 100644 --- a/eth/downloader/fakepeer.go +++ b/eth/downloader/fakepeer.go @@ -123,9 +123,10 @@ func (p *FakePeer) RequestHeadersByNumber(number uint64, amount int, skip int, r // corresponding to the specified block hashes. func (p *FakePeer) RequestBodies(hashes []common.Hash) error { var ( - txs [][]*types.Transaction - uncles [][]*types.Header - randomness []*types.Randomness + txs [][]*types.Transaction + uncles [][]*types.Header + randomness []*types.Randomness + epochSnarkData []*types.EpochSnarkData ) for _, hash := range hashes { block := rawdb.ReadBlock(p.db, hash, *p.hc.GetBlockNumber(hash)) @@ -133,8 +134,9 @@ func (p *FakePeer) RequestBodies(hashes []common.Hash) error { txs = append(txs, block.Transactions()) uncles = append(uncles, block.Uncles()) randomness = append(randomness, block.Randomness()) + epochSnarkData = append(epochSnarkData, block.EpochSnarkData()) } - p.dl.DeliverBodies(p.id, txs, uncles, randomness) + p.dl.DeliverBodies(p.id, txs, uncles, randomness, epochSnarkData) return nil } diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index ee9e86eecbe7..6e3ad37a2987 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -57,11 +57,12 @@ type fetchResult struct { Pending int // Number of data fetches still pending Hash common.Hash // Hash of the header to prevent recalculating - Header *types.Header - Uncles []*types.Header - Transactions types.Transactions - Receipts types.Receipts - Randomness *types.Randomness + Header *types.Header + Uncles []*types.Header + Transactions types.Transactions + Receipts types.Receipts + Randomness *types.Randomness + EpochSnarkData *types.EpochSnarkData } // queue represents hashes that are either need fetching or are being fetched @@ -766,7 +767,7 @@ func (q *queue) DeliverHeaders(id string, headers []*types.Header, headerProcCh // DeliverBodies injects a block body retrieval response into the results queue. // The method returns the number of blocks bodies accepted from the delivery and // also wakes any threads waiting for data delivery. -func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, uncleLists [][]*types.Header, randomnessList []*types.Randomness) (int, error) { +func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, uncleLists [][]*types.Header, randomnessList []*types.Randomness, epochSnarkDataList []*types.EpochSnarkData) (int, error) { q.lock.Lock() defer q.lock.Unlock() @@ -777,6 +778,7 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, uncleLi result.Transactions = txLists[index] result.Uncles = uncleLists[index] result.Randomness = randomnessList[index] + result.EpochSnarkData = epochSnarkDataList[index] return nil } return q.deliver(id, q.blockTaskPool, q.blockTaskQueue, q.blockPendPool, q.blockDonePool, bodyReqTimer, len(txLists), reconstruct) diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index f77e1ee6ec52..2655541bab84 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -199,18 +199,20 @@ func (tc *testChain) receipts(hashes []common.Hash) [][]*types.Receipt { } // bodies returns the block bodies of the given block hashes. -func (tc *testChain) bodies(hashes []common.Hash) ([][]*types.Transaction, [][]*types.Header, []*types.Randomness) { +func (tc *testChain) bodies(hashes []common.Hash) ([][]*types.Transaction, [][]*types.Header, []*types.Randomness, []*types.EpochSnarkData) { transactions := make([][]*types.Transaction, 0, len(hashes)) uncles := make([][]*types.Header, 0, len(hashes)) randomness := make([]*types.Randomness, 0, len(hashes)) + epochSnarkData := make([]*types.EpochSnarkData, 0, len(hashes)) for _, hash := range hashes { if block, ok := tc.blockm[hash]; ok { transactions = append(transactions, block.Transactions()) uncles = append(uncles, block.Uncles()) randomness = append(randomness, block.Randomness()) + epochSnarkData = append(epochSnarkData, block.EpochSnarkData()) } } - return transactions, uncles, randomness + return transactions, uncles, randomness, epochSnarkData } func (tc *testChain) hashToNumber(target common.Hash) (uint64, bool) { diff --git a/eth/downloader/types.go b/eth/downloader/types.go index b267cf3e25c1..b14249f730fa 100644 --- a/eth/downloader/types.go +++ b/eth/downloader/types.go @@ -44,10 +44,11 @@ func (p *headerPack) Stats() string { return fmt.Sprintf("%d", len(p.headers)) // bodyPack is a batch of block bodies returned by a peer. type bodyPack struct { - peerID string - transactions [][]*types.Transaction - uncles [][]*types.Header - randomness []*types.Randomness + peerID string + transactions [][]*types.Transaction + uncles [][]*types.Header + randomness []*types.Randomness + epochSnarkData []*types.EpochSnarkData } func (p *bodyPack) PeerId() string { return p.peerID } diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index 1985b2e59cac..e84d5b4d22e7 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -91,11 +91,12 @@ type headerFilterTask struct { // bodyFilterTask represents a batch of block bodies (transactions and uncles) // needing fetcher filtering. type bodyFilterTask struct { - peer string // The source peer of block bodies - transactions [][]*types.Transaction // Collection of transactions per block bodies - uncles [][]*types.Header // Collection of uncles per block bodies - randomness []*types.Randomness - time time.Time // Arrival time of the blocks' contents + peer string // The source peer of block bodies + transactions [][]*types.Transaction // Collection of transactions per block bodies + uncles [][]*types.Header // Collection of uncles per block bodies + randomness []*types.Randomness + epochSnarkData []*types.EpochSnarkData + time time.Time // Arrival time of the blocks' contents } // inject represents a schedules import operation. @@ -249,7 +250,7 @@ func (f *Fetcher) FilterHeaders(peer string, headers []*types.Header, time time. // FilterBodies extracts all the block bodies that were explicitly requested by // the fetcher, returning those that should be handled differently. -func (f *Fetcher) FilterBodies(peer string, transactions [][]*types.Transaction, uncles [][]*types.Header, randomness []*types.Randomness, time time.Time) ([][]*types.Transaction, [][]*types.Header, []*types.Randomness) { +func (f *Fetcher) FilterBodies(peer string, transactions [][]*types.Transaction, uncles [][]*types.Header, randomness []*types.Randomness, epochSnarkData []*types.EpochSnarkData, time time.Time) ([][]*types.Transaction, [][]*types.Header, []*types.Randomness, []*types.EpochSnarkData) { log.Trace("Filtering bodies", "peer", peer, "txs", len(transactions), "uncles", len(uncles)) // Send the filter channel to the fetcher @@ -258,20 +259,20 @@ func (f *Fetcher) FilterBodies(peer string, transactions [][]*types.Transaction, select { case f.bodyFilter <- filter: case <-f.quit: - return nil, nil, nil + return nil, nil, nil, nil } // Request the filtering of the body list select { - case filter <- &bodyFilterTask{peer: peer, transactions: transactions, uncles: uncles, randomness: randomness, time: time}: + case filter <- &bodyFilterTask{peer: peer, transactions: transactions, uncles: uncles, randomness: randomness, epochSnarkData: epochSnarkData, time: time}: case <-f.quit: - return nil, nil, nil + return nil, nil, nil, nil } // Retrieve the bodies remaining after filtering select { case task := <-filter: - return task.transactions, task.uncles, task.randomness + return task.transactions, task.uncles, task.randomness, task.epochSnarkData case <-f.quit: - return nil, nil, nil + return nil, nil, nil, nil } } @@ -506,7 +507,7 @@ func (f *Fetcher) loop() { bodyFilterInMeter.Mark(int64(len(task.transactions))) blocks := []*types.Block{} - for i := 0; i < len(task.transactions) && i < len(task.uncles) && i < len(task.randomness); i++ { + for i := 0; i < len(task.transactions) && i < len(task.uncles) && i < len(task.randomness) && i < len(task.epochSnarkData); i++ { // Match up a body to any possible completion request matched := false @@ -520,7 +521,7 @@ func (f *Fetcher) loop() { matched = true if f.getBlock(hash) == nil { - block := types.NewBlockWithHeader(announce.header).WithBody(task.transactions[i], task.uncles[i], task.randomness[i]) + block := types.NewBlockWithHeader(announce.header).WithBody(task.transactions[i], task.uncles[i], task.randomness[i], task.epochSnarkData[i]) block.ReceivedAt = task.time blocks = append(blocks, block) @@ -534,6 +535,7 @@ func (f *Fetcher) loop() { task.transactions = append(task.transactions[:i], task.transactions[i+1:]...) task.uncles = append(task.uncles[:i], task.uncles[i+1:]...) task.randomness = append(task.randomness[:i], task.randomness[i+1:]...) + task.epochSnarkData = append(task.epochSnarkData[:i], task.epochSnarkData[i+1:]...) i-- continue } diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go index c01aa0fe3023..5131d665107a 100644 --- a/eth/fetcher/fetcher_test.go +++ b/eth/fetcher/fetcher_test.go @@ -185,16 +185,18 @@ func (f *fetcherTester) makeBodyFetcher(peer string, blocks map[common.Hash]*typ transactions := make([][]*types.Transaction, 0, len(hashes)) uncles := make([][]*types.Header, 0, len(hashes)) randomness := make([]*types.Randomness, 0, len(hashes)) + epochSnarkData := make([]*types.EpochSnarkData, 0, len(hashes)) for _, hash := range hashes { if block, ok := closure[hash]; ok { transactions = append(transactions, block.Transactions()) uncles = append(uncles, block.Uncles()) randomness = append(randomness, block.Randomness()) + epochSnarkData = append(epochSnarkData, block.EpochSnarkData()) } } // Return on a new thread - go f.fetcher.FilterBodies(peer, transactions, uncles, randomness, time.Now().Add(drift)) + go f.fetcher.FilterBodies(peer, transactions, uncles, randomness, epochSnarkData, time.Now().Add(drift)) return nil } diff --git a/eth/handler.go b/eth/handler.go index 60147e3de23f..bfa5b6aea283 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -579,19 +579,21 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { transactions := make([][]*types.Transaction, len(request)) uncles := make([][]*types.Header, len(request)) randomness := make([]*types.Randomness, len(request)) + epochSnarkData := make([]*types.EpochSnarkData, len(request)) for i, body := range request { transactions[i] = body.Transactions uncles[i] = body.Uncles randomness[i] = body.Randomness + epochSnarkData[i] = body.EpochSnarkData } // Filter out any explicitly requested bodies, deliver the rest to the downloader - filter := len(transactions) > 0 || len(uncles) > 0 || len(randomness) > 0 + filter := len(transactions) > 0 || len(uncles) > 0 || len(randomness) > 0 || len(epochSnarkData) > 0 if filter { - transactions, uncles, randomness = pm.fetcher.FilterBodies(p.id, transactions, uncles, randomness, time.Now()) + transactions, uncles, randomness, epochSnarkData = pm.fetcher.FilterBodies(p.id, transactions, uncles, randomness, epochSnarkData, time.Now()) } - if len(transactions) > 0 || len(uncles) > 0 || len(randomness) > 0 || !filter { - err := pm.downloader.DeliverBodies(p.id, transactions, uncles, randomness) + if len(transactions) > 0 || len(uncles) > 0 || len(randomness) > 0 || len(epochSnarkData) > 0 || !filter { + err := pm.downloader.DeliverBodies(p.id, transactions, uncles, randomness, epochSnarkData) if err != nil { log.Debug("Failed to deliver bodies", "err", err) } diff --git a/eth/handler_test.go b/eth/handler_test.go index 56bb3c22486f..042e33d75680 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -278,7 +278,7 @@ func testGetBlockBodies(t *testing.T, protocol int) { block := pm.blockchain.GetBlockByNumber(uint64(num)) hashes = append(hashes, block.Hash()) if len(bodies) < tt.expected { - bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles(), Randomness: block.Randomness()}) + bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles(), Randomness: block.Randomness(), EpochSnarkData: block.EpochSnarkData()}) } break } @@ -288,7 +288,7 @@ func testGetBlockBodies(t *testing.T, protocol int) { hashes = append(hashes, hash) if tt.available[j] && len(bodies) < tt.expected { block := pm.blockchain.GetBlockByHash(hash) - bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles(), Randomness: block.Randomness()}) + bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles(), Randomness: block.Randomness(), EpochSnarkData: block.EpochSnarkData()}) } } // Send the hash request and verify the response diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index fd4c1d0c0b8b..8a6f46fc3fbc 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -79,10 +79,11 @@ func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Bl } type rpcBlock struct { - Hash common.Hash `json:"hash"` - Transactions []rpcTransaction `json:"transactions"` - UncleHashes []common.Hash `json:"uncles"` - Randomness *types.Randomness `json:"randomness"` + Hash common.Hash `json:"hash"` + Transactions []rpcTransaction `json:"transactions"` + UncleHashes []common.Hash `json:"uncles"` + Randomness *types.Randomness `json:"randomness"` + EpochSnarkData *types.EpochSnarkData `json:"epochSnarkData"` } func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) { @@ -147,7 +148,7 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface } txs[i] = tx.tx } - return types.NewBlockWithHeader(head).WithBody(txs, uncles, body.Randomness), nil + return types.NewBlockWithHeader(head).WithBody(txs, uncles, body.Randomness, body.EpochSnarkData), nil } // HeaderByHash returns the block header with the given hash. diff --git a/les/handler_test.go b/les/handler_test.go index 6d9b39f2c83b..a21b189913d9 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -226,7 +226,7 @@ func testGetBlockBodies(t *testing.T, protocol int) { block := bc.GetBlockByNumber(uint64(num)) hashes = append(hashes, block.Hash()) if len(bodies) < tt.expected { - bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles(), Randomness: block.Randomness()}) + bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles(), Randomness: block.Randomness(), EpochSnarkData: block.EpochSnarkData()}) } break } @@ -236,7 +236,7 @@ func testGetBlockBodies(t *testing.T, protocol int) { hashes = append(hashes, hash) if tt.available[j] && len(bodies) < tt.expected { block := bc.GetBlockByHash(hash) - bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles(), Randomness: block.Randomness()}) + bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles(), Randomness: block.Randomness(), EpochSnarkData: block.EpochSnarkData()}) } } reqID++ diff --git a/light/odr_util.go b/light/odr_util.go index d3eac4e03f32..46ca6c689042 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -121,7 +121,7 @@ func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint return nil, err } // Reassemble the block and return - return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles, body.Randomness), nil + return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles, body.Randomness, body.EpochSnarkData), nil } // GetBlockReceipts retrieves the receipts generated by the transactions included diff --git a/miner/worker_test.go b/miner/worker_test.go index c6bfdb4f208a..91b94991d883 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -193,54 +193,54 @@ func getAuthorizedIstanbulEngine() consensus.Istanbul { return crypto.Sign(data, testBankKey) } - signHashBLSFn := func(_ accounts.Account, data []byte) ([]byte, error) { + signHashBLSFn := func(_ accounts.Account, data []byte) (blscrypto.SerializedSignature, error) { privateKeyBytes, err := blscrypto.ECDSAToBLS(testBankKey) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer privateKey.Destroy() signature, err := privateKey.SignMessage(data, []byte{}, false) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer signature.Destroy() signatureBytes, err := signature.Serialize() if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } - signMessageBLSFn := func(_ accounts.Account, msg []byte, extraData []byte) ([]byte, error) { + signMessageBLSFn := func(_ accounts.Account, msg []byte, extraData []byte) (blscrypto.SerializedSignature, error) { privateKeyBytes, err := blscrypto.ECDSAToBLS(testBankKey) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer privateKey.Destroy() signature, err := privateKey.SignMessage(msg, extraData, true) if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } defer signature.Destroy() signatureBytes, err := signature.Serialize() if err != nil { - return nil, err + return blscrypto.SerializedSignature{}, err } - return signatureBytes, nil + return blscrypto.SerializedSignatureFromBytes(signatureBytes) } config := istanbul.DefaultConfig diff --git a/vendor/github.com/celo-org/bls-zexe/bls/algebra/src/curve/hash/mod.rs b/vendor/github.com/celo-org/bls-zexe/bls/algebra/src/curve/hash/mod.rs index 60329f91a095..1890a08d01fc 100644 --- a/vendor/github.com/celo-org/bls-zexe/bls/algebra/src/curve/hash/mod.rs +++ b/vendor/github.com/celo-org/bls-zexe/bls/algebra/src/curve/hash/mod.rs @@ -9,11 +9,19 @@ use std::{ #[derive(Debug)] pub enum HashToCurveError { CannotFindPoint, + SmallOrderPoint, } impl Display for HashToCurveError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "cannot find point") + match self { + HashToCurveError::CannotFindPoint => { + write!(f, "cannot find point") + } + HashToCurveError::SmallOrderPoint => { + write!(f, "got small order point") + } + } } } diff --git a/vendor/github.com/celo-org/bls-zexe/bls/algebra/src/curve/hash/try_and_increment.rs b/vendor/github.com/celo-org/bls-zexe/bls/algebra/src/curve/hash/try_and_increment.rs index de26987b0009..beb0ec5c3e31 100644 --- a/vendor/github.com/celo-org/bls-zexe/bls/algebra/src/curve/hash/try_and_increment.rs +++ b/vendor/github.com/celo-org/bls-zexe/bls/algebra/src/curve/hash/try_and_increment.rs @@ -8,17 +8,13 @@ use crate::{ use byteorder::WriteBytesExt; use hex; -use algebra::{ - curves::{ - models::{ - bls12::{Bls12Parameters, G1Affine, G2Affine, G1Projective, G2Projective}, - ModelParameters, SWModelParameters, - }, - AffineCurve, +use algebra::{curves::{ + models::{ + bls12::{Bls12Parameters, G1Affine, G2Affine, G1Projective, G2Projective}, + ModelParameters, SWModelParameters, }, - fields::{Field, Fp2, FpParameters, PrimeField, SquareRootField}, - bytes::FromBytes, -}; + AffineCurve, +}, fields::{Field, Fp2, FpParameters, PrimeField, SquareRootField}, bytes::FromBytes, Group}; use std::error::Error; #[allow(dead_code)] @@ -134,9 +130,13 @@ impl<'a, H: XOF> HashToG1 for TryAndIncrement<'a, H> { c ); end_timer!(hash_loop_time); - return Ok(cofactor::scale_by_cofactor_g1::

( + let scaled = cofactor::scale_by_cofactor_g1::

( &x.into_projective(), - )); + ); + if scaled.is_zero() { + return Err(HashToCurveError::SmallOrderPoint)?; + } + return Ok(scaled); } } } @@ -191,9 +191,13 @@ impl<'a, H: XOF> HashToG2 for TryAndIncrement<'a, H> { c ); end_timer!(hash_loop_time); - return Ok(cofactor::scale_by_cofactor_fuentes::

( + let scaled = cofactor::scale_by_cofactor_fuentes::

( &x.into_projective(), - )); + ); + if scaled.is_zero() { + return Err(HashToCurveError::SmallOrderPoint)?; + } + return Ok(scaled); } } } diff --git a/vendor/github.com/celo-org/bls-zexe/go/bls.go b/vendor/github.com/celo-org/bls-zexe/go/bls.go index be8feacae157..57096a52a7bd 100644 --- a/vendor/github.com/celo-org/bls-zexe/go/bls.go +++ b/vendor/github.com/celo-org/bls-zexe/go/bls.go @@ -279,14 +279,14 @@ func AggregateSignatures(signatures []*Signature) (*Signature, error) { return aggregatedSignature, nil } -func EncodeEpochToBytes(epochIndex uint16, maximumNonSigners uint32, aggregatedPublicKey *PublicKey, addedPublicKeys []*PublicKey) ([]byte, error) { +func EncodeEpochToBytes(epochIndex uint16, maximumNonSignersPlusOne uint32, aggregatedPublicKey *PublicKey, addedPublicKeys []*PublicKey) ([]byte, error) { publicKeysPtrs := []*C.struct_PublicKey{} for _, pk := range addedPublicKeys { publicKeysPtrs = append(publicKeysPtrs, pk.ptr) } var bytes *C.uchar var size C.int - success := C.encode_epoch_block_to_bytes(C.ushort(epochIndex), C.uint(maximumNonSigners), aggregatedPublicKey.ptr, (**C.struct_PublicKey)(unsafe.Pointer(&publicKeysPtrs[0])), C.int(len(publicKeysPtrs)), &bytes, &size) + success := C.encode_epoch_block_to_bytes(C.ushort(epochIndex), C.uint(maximumNonSignersPlusOne), aggregatedPublicKey.ptr, (**C.struct_PublicKey)(unsafe.Pointer(&publicKeysPtrs[0])), C.int(len(publicKeysPtrs)), &bytes, &size) if !success { return nil, GeneralError } diff --git a/vendor/github.com/celo-org/bls-zexe/go/cmd/example/main.go b/vendor/github.com/celo-org/bls-zexe/go/cmd/example/main.go index 6f94deb0d73a..8cb10599195e 100644 --- a/vendor/github.com/celo-org/bls-zexe/go/cmd/example/main.go +++ b/vendor/github.com/celo-org/bls-zexe/go/cmd/example/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "github.com/celo-org/bls-zexe" + "github.com/celo-org/bls-zexe/go" ) func main() { diff --git a/vendor/github.com/celo-org/bls-zexe/go/go.mod b/vendor/github.com/celo-org/bls-zexe/go/go.mod index ea61fe2d3b54..f0aa288c2fff 100644 --- a/vendor/github.com/celo-org/bls-zexe/go/go.mod +++ b/vendor/github.com/celo-org/bls-zexe/go/go.mod @@ -1,3 +1,3 @@ -module github.com/celo-org/bls-zexe +module github.com/celo-org/bls-zexe/go go 1.12 diff --git a/vendor/vendor.json b/vendor/vendor.json index 4b236f5691c4..7e61d44e18df 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -63,10 +63,10 @@ "revisionTime": "2017-11-28T15:02:46Z" }, { - "checksumSHA1": "/yX36dBBvVRz+wSFLlRAy+zqugc=", + "checksumSHA1": "tI6q8Vozcsz0qs89CNiEw9b1sgo=", "path": "github.com/celo-org/bls-zexe", - "revision": "4c80fd83fe7efefe2b1df39e02474139fc95eb57", - "revisionTime": "2019-11-25T13:39:18Z", + "revision": "17a63cfa2a56587ce5f6a4fce1790100c259274f", + "revisionTime": "2020-01-12T08:31:31Z", "tree": true }, {