Reduce deposit memory (#7478)

* remove deposit proof and pending deposits

* wip

* wip

* wip

* clean up logs/comments

* function for pruning deposits and feature flag

* remove log

* add flag to beacon flags

* addressed PR feedback from terence

* add test assertions for errors

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
Radosław Kapka 2020-10-12 20:10:49 +02:00 committed by GitHub
parent ac1a4a078c
commit 06d16a24b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 182 additions and 10 deletions

View File

@ -125,7 +125,17 @@ func (s *Service) onBlock(ctx context.Context, signed *ethpb.SignedBeaconBlock,
if err != nil {
return errors.Wrap(err, "could not fetch finalized state")
}
s.depositCache.InsertFinalizedDeposits(ctx, int64(finalizedState.Eth1Data().DepositCount-1))
// We update the cache up to the last deposit index in the finalized block's state.
// We can be confident that these deposits will be included in some block
// because the Eth1 follow distance makes such long-range reorgs extremely unlikely.
eth1DepositIndex := int64(finalizedState.Eth1Data().DepositCount - 1)
s.depositCache.InsertFinalizedDeposits(ctx, eth1DepositIndex)
if featureconfig.Get().EnablePruningDepositProofs {
// Deposit proofs are only used during state transition and can be safely removed to save space.
if err = s.depositCache.PruneProofs(ctx, eth1DepositIndex); err != nil {
return errors.Wrap(err, "could not prune deposit proofs")
}
}
}
defer reportAttestationInclusion(b)

View File

@ -258,3 +258,28 @@ func (dc *DepositCache) NonFinalizedDeposits(ctx context.Context, untilBlk *big.
return deposits
}
// PruneProofs removes proofs from all deposits whose index is equal or less than untilDepositIndex.
func (dc *DepositCache) PruneProofs(ctx context.Context, untilDepositIndex int64) error {
ctx, span := trace.StartSpan(ctx, "DepositsCache.PruneProofs")
defer span.End()
dc.depositsLock.Lock()
defer dc.depositsLock.Unlock()
if untilDepositIndex > int64(len(dc.deposits)) {
untilDepositIndex = int64(len(dc.deposits) - 1)
}
for i := untilDepositIndex; i >= 0; i-- {
if ctx.Err() != nil {
return ctx.Err()
}
// Finding a nil proof means that all proofs up to this deposit have been already pruned.
if dc.deposits[i].Deposit.Proof == nil {
break
}
dc.deposits[i].Deposit.Proof = nil
}
return nil
}

View File

@ -573,3 +573,137 @@ func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *test
deps := dc.NonFinalizedDeposits(context.Background(), big.NewInt(10))
assert.Equal(t, 1, len(deps))
}
func TestPruneProofs_Ok(t *testing.T) {
dc, err := New()
require.NoError(t, err)
deposits := []struct {
blkNum uint64
deposit *ethpb.Deposit
index int64
}{
{
blkNum: 0,
deposit: &ethpb.Deposit{Proof: makeDepositProof()},
index: 0,
},
{
blkNum: 0,
deposit: &ethpb.Deposit{Proof: makeDepositProof()},
index: 1,
},
{
blkNum: 0,
deposit: &ethpb.Deposit{Proof: makeDepositProof()},
index: 2,
},
{
blkNum: 0,
deposit: &ethpb.Deposit{Proof: makeDepositProof()},
index: 3,
},
}
for _, ins := range deposits {
dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})
}
require.NoError(t, dc.PruneProofs(context.Background(), 1))
assert.DeepEqual(t, ([][]byte)(nil), dc.deposits[0].Deposit.Proof)
assert.DeepEqual(t, ([][]byte)(nil), dc.deposits[1].Deposit.Proof)
assert.NotNil(t, dc.deposits[2].Deposit.Proof)
assert.NotNil(t, dc.deposits[3].Deposit.Proof)
}
func TestPruneProofs_SomeAlreadyPruned(t *testing.T) {
dc, err := New()
require.NoError(t, err)
deposits := []struct {
blkNum uint64
deposit *ethpb.Deposit
index int64
}{
{
blkNum: 0,
deposit: &ethpb.Deposit{Proof: nil},
index: 0,
},
{
blkNum: 0,
deposit: &ethpb.Deposit{Proof: nil},
index: 1,
},
{
blkNum: 0,
deposit: &ethpb.Deposit{Proof: makeDepositProof()},
index: 2,
},
{
blkNum: 0,
deposit: &ethpb.Deposit{Proof: makeDepositProof()},
index: 3,
},
}
for _, ins := range deposits {
dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})
}
require.NoError(t, dc.PruneProofs(context.Background(), 2))
assert.DeepEqual(t, ([][]byte)(nil), dc.deposits[2].Deposit.Proof)
}
func TestPruneProofs_PruneAllWhenDepositIndexTooBig(t *testing.T) {
dc, err := New()
require.NoError(t, err)
deposits := []struct {
blkNum uint64
deposit *ethpb.Deposit
index int64
}{
{
blkNum: 0,
deposit: &ethpb.Deposit{Proof: makeDepositProof()},
index: 0,
},
{
blkNum: 0,
deposit: &ethpb.Deposit{Proof: makeDepositProof()},
index: 1,
},
{
blkNum: 0,
deposit: &ethpb.Deposit{Proof: makeDepositProof()},
index: 2,
},
{
blkNum: 0,
deposit: &ethpb.Deposit{Proof: makeDepositProof()},
index: 3,
},
}
for _, ins := range deposits {
dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})
}
require.NoError(t, dc.PruneProofs(context.Background(), 99))
assert.DeepEqual(t, ([][]byte)(nil), dc.deposits[0].Deposit.Proof)
assert.DeepEqual(t, ([][]byte)(nil), dc.deposits[1].Deposit.Proof)
assert.DeepEqual(t, ([][]byte)(nil), dc.deposits[2].Deposit.Proof)
assert.DeepEqual(t, ([][]byte)(nil), dc.deposits[3].Deposit.Proof)
}
func makeDepositProof() [][]byte {
proof := make([][]byte, int(params.BeaconConfig().DepositContractTreeDepth)+1)
for i := range proof {
proof[i] = make([]byte, 32)
}
return proof
}

View File

@ -9,7 +9,6 @@ import (
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
)
@ -29,14 +28,6 @@ func TestInsertPendingDeposit_ignoresNilDeposit(t *testing.T) {
assert.Equal(t, 0, len(dc.pendingDeposits))
}
func makeDepositProof() [][]byte {
proof := make([][]byte, int(params.BeaconConfig().DepositContractTreeDepth)+1)
for i := range proof {
proof[i] = make([]byte, 32)
}
return proof
}
func TestRemovePendingDeposit_OK(t *testing.T) {
db := DepositCache{}
proof1 := makeDepositProof()

View File

@ -68,6 +68,7 @@ type Flags struct {
EnableEth1DataMajorityVote bool // EnableEth1DataMajorityVote uses the Voting With The Majority algorithm to vote for eth1data.
EnableAttBroadcastDiscoveryAttempts bool // EnableAttBroadcastDiscoveryAttempts allows the p2p service to attempt to ensure a subnet peer is present before broadcasting an attestation.
EnablePeerScorer bool // EnablePeerScorer enables experimental peer scoring in p2p.
EnablePruningDepositProofs bool // EnablePruningDepositProofs enables pruning deposit proofs which significantly reduces the size of a deposit
// DisableForkChoice disables using LMD-GHOST fork choice to update
// the head of the chain based on attestations and instead accepts any valid received block
@ -297,6 +298,10 @@ func ConfigureBeaconChain(ctx *cli.Context) {
log.Warn("Enabling new BLS library blst")
cfg.EnableBlst = true
}
if ctx.Bool(enablePruningDepositProofs.Name) {
log.Warn("Enabling pruning deposit proofs")
cfg.EnablePruningDepositProofs = true
}
Init(cfg)
}

View File

@ -184,6 +184,10 @@ var (
Name: "use-check-point-cache",
Usage: "Enables check point info caching",
}
enablePruningDepositProofs = &cli.BoolFlag{
Name: "enable-pruning-deposit-proofs",
Usage: "Enables pruning deposit proofs when they are no longer needed. This significantly reduces deposit size.",
}
)
// devModeFlags holds list of flags that are set when development mode is on.
@ -192,6 +196,7 @@ var devModeFlags = []cli.Flag{
enableEth1DataMajorityVote,
enableAttBroadcastDiscoveryAttempts,
enablePeerScorer,
enablePruningDepositProofs,
}
// Deprecated flags list.
@ -715,6 +720,7 @@ var BeaconChainFlags = append(deprecatedFlags, []cli.Flag{
enableAttBroadcastDiscoveryAttempts,
enablePeerScorer,
checkPtInfoCache,
enablePruningDepositProofs,
}...)
// E2EBeaconChainFlags contains a list of the beacon chain feature flags to be tested in E2E.
@ -726,4 +732,5 @@ var E2EBeaconChainFlags = []string{
"--dev",
"--enable-eth1-data-majority-vote",
"--use-check-point-cache",
"--enable-pruning-deposit-proofs",
}