Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: resync the batchstore #3159

Merged
merged 13 commits into from
Aug 29, 2022
6 changes: 3 additions & 3 deletions pkg/bzz/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@ func NewAddress(signer crypto.Signer, underlay ma.Multiaddr, overlay swarm.Addre
}, nil
}

func ParseAddress(underlay, overlay, signature, trxHash, blockHash []byte, validateOverlay bool, networkID uint64) (*Address, error) {
func ParseAddress(underlay, overlay, signature, nonce []byte, validateOverlay bool, networkID uint64) (*Address, error) {
recoveredPK, err := crypto.Recover(signature, generateSignData(underlay, overlay, networkID))
if err != nil {
return nil, ErrInvalidAddress
}

if validateOverlay {
recoveredOverlay, err := crypto.NewOverlayAddress(*recoveredPK, networkID, blockHash)
recoveredOverlay, err := crypto.NewOverlayAddress(*recoveredPK, networkID, nonce)
if err != nil {
return nil, ErrInvalidAddress
}
Expand All @@ -91,7 +91,7 @@ func ParseAddress(underlay, overlay, signature, trxHash, blockHash []byte, valid
Underlay: multiUnderlay,
Overlay: swarm.NewAddress(overlay),
Signature: signature,
Transaction: trxHash,
Transaction: nonce,
EthereumAddress: ethAddress,
}, nil
}
Expand Down
9 changes: 4 additions & 5 deletions pkg/bzz/address_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,25 @@ func TestBzzAddress(t *testing.T) {
t.Fatal(err)
}

trxHash := common.HexToHash("0x1").Bytes()
blockHash := common.HexToHash("0x2").Bytes()
nonce := common.HexToHash("0x2").Bytes()

privateKey1, err := crypto.GenerateSecp256k1Key()
if err != nil {
t.Fatal(err)
}

overlay, err := crypto.NewOverlayAddress(privateKey1.PublicKey, 3, blockHash)
overlay, err := crypto.NewOverlayAddress(privateKey1.PublicKey, 3, nonce)
if err != nil {
t.Fatal(err)
}
signer1 := crypto.NewDefaultSigner(privateKey1)

bzzAddress, err := bzz.NewAddress(signer1, node1ma, overlay, 3, trxHash)
bzzAddress, err := bzz.NewAddress(signer1, node1ma, overlay, 3, nonce)
if err != nil {
t.Fatal(err)
}

bzzAddress2, err := bzz.ParseAddress(node1ma.Bytes(), overlay.Bytes(), bzzAddress.Signature, trxHash, blockHash, true, 3)
bzzAddress2, err := bzz.ParseAddress(node1ma.Bytes(), overlay.Bytes(), bzzAddress.Signature, nonce, true, 3)
if err != nil {
t.Fatal(err)
}
Expand Down
9 changes: 5 additions & 4 deletions pkg/config/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ var (
goerliChainID = int64(5)
xdaiChainID = int64(100)
// start block
goerliStartBlock = uint64(4933174)
xdaiStartBlock = uint64(16515648)
// replace this with
goerliStartBlock = uint64(7457394)
xdaiStartBlock = uint64(23862394)
// factory address
goerliContractAddress = common.HexToAddress("0x0c9de531dcb38b758fe8a2c163444a5e54ee0db2")
xdaiContractAddress = common.HexToAddress("0x0FDc5429C50e2a39066D8A94F3e2D2476fcc3b85")
goerliFactoryAddress = common.HexToAddress("0x73c412512E1cA0be3b89b77aB3466dA6A1B9d273")
xdaiFactoryAddress = common.HexToAddress("0xc2d5a532cf69aa9a1378737d8ccdef884b6e7420")
goerliLegacyFactoryAddress = common.HexToAddress("0xf0277caffea72734853b834afc9892461ea18474")
// postage stamp
goerliPostageStampContractAddress = common.HexToAddress("0x621e455C4a139f5C4e4A8122Ce55Dc21630769E4")
xdaiPostageStampContractAddress = common.HexToAddress("0x6a1a21eca3ab28be85c7ba22b2d6eae5907c900e")
goerliPostageStampContractAddress = common.HexToAddress("0x07456430a9878626ba42d4A26D5AfDa0A0Ca9D26")
xdaiPostageStampContractAddress = common.HexToAddress("0x52102F54CdfA1cC9386E34957FD14A80680e9Ba3")
)

type ChainConfig struct {
Expand Down
17 changes: 10 additions & 7 deletions pkg/crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,31 @@ const (
)

// NewOverlayAddress constructs a Swarm Address from ECDSA public key.
func NewOverlayAddress(p ecdsa.PublicKey, networkID uint64, blockHash []byte) (swarm.Address, error) {
func NewOverlayAddress(p ecdsa.PublicKey, networkID uint64, nonce []byte) (swarm.Address, error) {

ethAddr, err := NewEthereumAddress(p)
if err != nil {
return swarm.ZeroAddress, err
}

if len(blockHash) != 32 {
if len(nonce) != 32 {
return swarm.ZeroAddress, ErrBadHashLength
}

return NewOverlayFromEthereumAddress(ethAddr, networkID, blockHash), nil
return NewOverlayFromEthereumAddress(ethAddr, networkID, nonce)
}

// NewOverlayFromEthereumAddress constructs a Swarm Address for an Ethereum address.
func NewOverlayFromEthereumAddress(ethAddr []byte, networkID uint64, blockHash []byte) swarm.Address {
func NewOverlayFromEthereumAddress(ethAddr []byte, networkID uint64, nonce []byte) (swarm.Address, error) {
netIDBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(netIDBytes, networkID)
data := append(ethAddr, netIDBytes...)
data = append(data, blockHash...)
h := sha3.Sum256(data)
return swarm.NewAddress(h[:])
data = append(data, nonce...)
h, err := LegacyKeccak256(data)
if err != nil {
return swarm.ZeroAddress, err
}
return swarm.NewAddress(h[:]), nil
}

// GenerateSecp256k1Key generates an ECDSA private key using
Expand Down
12 changes: 6 additions & 6 deletions pkg/node/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"github.com/ethersphere/bee/pkg/log"
"github.com/ethersphere/bee/pkg/manifest"
"github.com/ethersphere/bee/pkg/netstore"
"github.com/ethersphere/bee/pkg/p2p"
"github.com/ethersphere/bee/pkg/p2p/libp2p"
"github.com/ethersphere/bee/pkg/postage"
"github.com/ethersphere/bee/pkg/pricer"
Expand All @@ -50,7 +49,9 @@ import (
)

var (
snapshotFeed = swarm.MustParseHexAddress("b181b084df07a550c9fc0007110bff67000fa92a090af6c5212fe8e19f888a28")
// zeroed out while waiting to be replacement for the new snapshot feed address
// must be different to avoid stale reads on the old contract
snapshotFeed = swarm.MustParseHexAddress("0000000000000000000000000000000000000000000000000000000000000000")
errDataMismatch = errors.New("data length mismatch")
)

Expand All @@ -63,13 +64,12 @@ const (
func bootstrapNode(
addr string,
swarmAddress swarm.Address,
txHash []byte,
nonce []byte,
chainID int64,
overlayEthAddress common.Address,
addressbook addressbook.Interface,
bootnodes []ma.Multiaddr,
lightNodes *lightnode.Container,
senderMatcher p2p.SenderMatcher,
chequebookService chequebook.Service,
chequeStore chequebook.ChequeStore,
cashoutService chequebook.CashoutService,
Expand Down Expand Up @@ -102,13 +102,13 @@ func bootstrapNode(
retErr = multierror.Append(new(multierror.Error), retErr, b.Shutdown()).ErrorOrNil()
}()

p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, senderMatcher, logger, tracer, libp2p.Options{
p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, logger, tracer, libp2p.Options{
PrivateKey: libp2pPrivateKey,
NATAddr: o.NATAddr,
EnableWS: o.EnableWS,
WelcomeMessage: o.WelcomeMessage,
FullNode: false,
Transaction: txHash,
Nonce: nonce,
})
if err != nil {
return nil, fmt.Errorf("p2p service: %w", err)
Expand Down
79 changes: 56 additions & 23 deletions pkg/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ package node
import (
"context"
"crypto/ecdsa"
"encoding/binary"
"errors"
"fmt"
"io"
stdlog "log"
"math"
"math/big"
"net"
"net/http"
Expand All @@ -24,7 +26,6 @@ import (
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/bee/pkg/accounting"
"github.com/ethersphere/bee/pkg/addressbook"
"github.com/ethersphere/bee/pkg/api"
Expand Down Expand Up @@ -239,7 +240,7 @@ func NewBee(interrupt chan struct{}, addr string, publicKey *ecdsa.PublicKey, si
// due to a migration or it's a fresh install.
batchStoreExists, err := batchStoreExists(stateStore)
if err != nil {
return nil, err
return nil, fmt.Errorf("batchstore: exists: %w", err)
}

addressbook := addressbook.New(stateStore)
Expand Down Expand Up @@ -454,27 +455,66 @@ func NewBee(interrupt chan struct{}, addr string, publicKey *ecdsa.PublicKey, si
return nil, err
}

var (
blockHash []byte
txHash []byte
)

txHash, err = GetTxHash(stateStore, logger, o.Transaction)
// if theres a previous transaction hash, and not a new chequebook deployment on a node starting from scratch
// get old overlay
// mine nonce that gives similar new overlay
nonce, nonceExists, err := overlayNonceExists(stateStore)
if err != nil {
return nil, fmt.Errorf("invalid transaction hash: %w", err)
return nil, fmt.Errorf("check presence of nonce: %w", err)
}
if !nonceExists {
nonce = make([]byte, 32)
}

blockHash, err = GetTxNextBlock(p2pCtx, logger, chainBackend, transactionMonitor, pollingInterval, txHash, o.BlockHash)
existingOverlay, err := GetExistingOverlay(stateStore)
if err != nil {
return nil, fmt.Errorf("invalid block hash: %w", err)
if !errors.Is(err, storage.ErrNotFound) {
return nil, fmt.Errorf("get existing overlay: %w", err)
}
logger.Warning("existing overlay", "error", err)
}

swarmAddress, err := crypto.NewOverlayAddress(*pubKey, networkID, blockHash)
if err == nil && o.FullNodeMode && !nonceExists {
newOverlayCandidate := swarm.ZeroAddress
j := uint64(0)
limit := math.Pow(2, 34)
for prox := uint8(0); prox < swarm.MaxPO && j < uint64(limit); j++ {
binary.LittleEndian.PutUint64(nonce, j)
if (j/1000000)*1000000 == j {
logger.Info("finding new overlay corresponding to previous overlay with nonce", "nonce", nonce)
}
newOverlayCandidate, err = crypto.NewOverlayAddress(*pubKey, networkID, nonce)
if err == nil {
prox = swarm.Proximity(existingOverlay.Bytes(), newOverlayCandidate.Bytes())
} else {
logger.Info("error finding new overlay", "error", err, "nonce", nonce)
}
}

foundProximity := swarm.Proximity(existingOverlay.Bytes(), newOverlayCandidate.Bytes())
if foundProximity < swarm.MaxPO {
return nil, fmt.Errorf("mining new overlay address failed")
}
}

swarmAddress, err := crypto.NewOverlayAddress(*pubKey, networkID, nonce)
if err != nil {
return nil, fmt.Errorf("compute overlay address: %w", err)
}
logger.Info("using overlay address", "address", swarmAddress)

if !nonceExists {
err := setOverlayNonce(stateStore, nonce)
if err != nil {
return nil, fmt.Errorf("statestore: save new overlay nonce: %w", err)
}

err = SetOverlayInStore(swarmAddress, stateStore)
if err != nil {
return nil, fmt.Errorf("statestore: save new overlay: %w", err)
}
}

apiService.SetSwarmAddress(&swarmAddress)

if err = CheckOverlayWithStore(swarmAddress, stateStore); err != nil {
Expand All @@ -483,12 +523,6 @@ func NewBee(interrupt chan struct{}, addr string, publicKey *ecdsa.PublicKey, si

lightNodes := lightnode.NewContainer(swarmAddress)

senderMatcher := transaction.NewMatcher(chainBackend, types.NewLondonSigner(big.NewInt(chainID)), stateStore, chainEnabled)
_, err = senderMatcher.Matches(p2pCtx, txHash, networkID, swarmAddress, true)
if err != nil {
return nil, fmt.Errorf("identity transaction verification failed: %w", err)
}

var bootnodes []ma.Multiaddr

for _, a := range o.Bootnodes {
Expand Down Expand Up @@ -534,13 +568,12 @@ func NewBee(interrupt chan struct{}, addr string, publicKey *ecdsa.PublicKey, si
initBatchState, err = bootstrapNode(
addr,
swarmAddress,
txHash,
nonce,
chainID,
overlayEthAddress,
addressbook,
bootnodes,
lightNodes,
senderMatcher,
chequebookService,
chequeStore,
cashoutService,
Expand All @@ -558,13 +591,13 @@ func NewBee(interrupt chan struct{}, addr string, publicKey *ecdsa.PublicKey, si
}
}

p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, senderMatcher, logger, tracer, libp2p.Options{
p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, logger, tracer, libp2p.Options{
PrivateKey: libp2pPrivateKey,
NATAddr: o.NATAddr,
EnableWS: o.EnableWS,
WelcomeMessage: o.WelcomeMessage,
FullNode: o.FullNodeMode,
Transaction: txHash,
Nonce: nonce,
ValidateOverlay: chainEnabled,
})
if err != nil {
Expand Down Expand Up @@ -827,7 +860,7 @@ func NewBee(interrupt chan struct{}, addr string, publicKey *ecdsa.PublicKey, si

pinningService := pinning.NewService(storer, stateStore, traversalService)

pushSyncProtocol := pushsync.New(swarmAddress, blockHash, p2ps, storer, kad, tagService, o.FullNodeMode, pssService.TryUnwrap, validStamp, logger, acc, pricer, signer, tracer, warmupTime)
pushSyncProtocol := pushsync.New(swarmAddress, nonce, p2ps, storer, kad, tagService, o.FullNodeMode, pssService.TryUnwrap, validStamp, logger, acc, pricer, signer, tracer, warmupTime)

// set the pushSyncer in the PSS
pssService.SetPushSyncer(pushSyncProtocol)
Expand Down
37 changes: 35 additions & 2 deletions pkg/node/statestore.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,28 @@ func InitStateStore(logger log.Logger, dataDir string) (storage.StateStorer, err
}

const secureOverlayKey = "non-mineable-overlay"
const noncedOverlayKey = "nonce-overlay"

func GetExistingOverlay(storer storage.StateStorer) (swarm.Address, error) {
var storedOverlay swarm.Address
err := storer.Get(secureOverlayKey, &storedOverlay)
if err != nil {
return swarm.ZeroAddress, err
}

return storedOverlay, nil
}

// CheckOverlayWithStore checks the overlay is the same as stored in the statestore
func CheckOverlayWithStore(overlay swarm.Address, storer storage.StateStorer) error {

var storedOverlay swarm.Address
err := storer.Get(secureOverlayKey, &storedOverlay)
err := storer.Get(noncedOverlayKey, &storedOverlay)
if err != nil {
if !errors.Is(err, storage.ErrNotFound) {
return err
}
return storer.Put(secureOverlayKey, overlay)
return storer.Put(noncedOverlayKey, overlay)
}

if !storedOverlay.Equal(overlay) {
Expand All @@ -46,3 +57,25 @@ func CheckOverlayWithStore(overlay swarm.Address, storer storage.StateStorer) er

return nil
}

// SetOverlayInStore sets the overlay stored in the statestore (for purpose of overlay migration)
func SetOverlayInStore(overlay swarm.Address, storer storage.StateStorer) error {
return storer.Put(noncedOverlayKey, overlay)
}

const OverlayNonce = "overlayV2_nonce"

func overlayNonceExists(s storage.StateStorer) ([]byte, bool, error) {
overlayNonce := make([]byte, 32)
if err := s.Get(OverlayNonce, &overlayNonce); err != nil {
if errors.Is(err, storage.ErrNotFound) {
return nil, false, nil
}
return nil, false, err
}
return overlayNonce, true, nil
}

func setOverlayNonce(s storage.StateStorer, overlayNonce []byte) error {
return s.Put(OverlayNonce, overlayNonce)
}
Loading