Skip to content

Commit

Permalink
restrict empty block production to 1 empty block per emptyBlockTimeout (
Browse files Browse the repository at this point in the history
#1251)

- Introduces emptyBlockTimeout config to control the frequency with which the leader
can propose empty blocks if no transactions are available. setting it to 0 disables it. 
- Resolution expiry is now tracked using a timestamp rather than the number of blocks
- event store now tracks in-memory the events without resolutions
- network performance improvements especially with blocksync
- enter into catchup mode only if no valid messages have been received for a duration of emptyBlocktimeout + blkPropTimeout.
  • Loading branch information
charithabandi authored Jan 22, 2025
1 parent 88353e6 commit 1c3700e
Show file tree
Hide file tree
Showing 45 changed files with 614 additions and 303 deletions.
5 changes: 3 additions & 2 deletions app/migration/proposal_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"math"
"time"

"github.com/spf13/cobra"

Expand Down Expand Up @@ -53,7 +54,7 @@ func proposalStatusCmd() *cobra.Command {

type MigrationStatus struct {
ProposalID *types.UUID
ExpiresAt int64 `json:"expires_at"` // ExpiresAt is the block height at which the migration proposal expires
ExpiresAt time.Time `json:"expires_at"` // ExpiresAt is the block height at which the migration proposal expires
Board []*types.AccountID `json:"board"` // Board is the list of validators who are eligible to vote on the migration proposal
Approved []bool `json:"approved"` // Approved is the list of bools indicating if the corresponding validator approved the migration proposal
}
Expand All @@ -74,7 +75,7 @@ func (m *MigrationStatus) MarshalText() ([]byte, error) {
var msg bytes.Buffer
msg.WriteString("Migration Status:\n")
msg.WriteString(fmt.Sprintf("\tProposal ID: %s\n", m.ProposalID.String()))
msg.WriteString(fmt.Sprintf("\tExpires At: %d\n", m.ExpiresAt))
msg.WriteString(fmt.Sprintf("\tExpires At: %s\n", m.ExpiresAt.String()))
msg.WriteString(fmt.Sprintf("\tApprovals Received: %d (needed %d)\n", approved, needed))

for i := range m.Board {
Expand Down
9 changes: 5 additions & 4 deletions app/node/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,10 @@ func buildDB(ctx context.Context, d *coreDependencies, closers *closeFuncs) *pg.
// adjustExpiration = true
// }

// err = migrations.CleanupResolutionsAfterMigration(d.ctx, db, adjustExpiration, startHeight)
// if err != nil {
// failBuild(err, "failed to cleanup resolutions after snapshot restore")
// }
err = migrations.CleanupResolutionsAfterMigration(d.ctx, db)
if err != nil {
failBuild(err, "failed to cleanup resolutions after snapshot restore")
}

if err = db.EnsureFullReplicaIdentityDatasets(d.ctx); err != nil {
failBuild(err, "failed enable full replica identity on user datasets")
Expand Down Expand Up @@ -404,6 +404,7 @@ func buildConsensusEngine(_ context.Context, d *coreDependencies, db *pg.DB,
Mempool: mempool,
Logger: d.logger.New("CONS"),
ProposeTimeout: time.Duration(d.cfg.Consensus.ProposeTimeout),
EmptyBlockTimeout: time.Duration(d.cfg.Consensus.EmptyBlockTimeout),
BlockProposalInterval: time.Duration(d.cfg.Consensus.BlockProposalInterval),
BlockAnnInterval: time.Duration(d.cfg.Consensus.BlockAnnInterval),
BroadcastTxTimeout: time.Duration(d.cfg.RPC.BroadcastTxTimeout),
Expand Down
2 changes: 1 addition & 1 deletion app/params/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func (rs MsgResolutionStatus) MarshalText() ([]byte, error) {
var buf bytes.Buffer
fmt.Fprintf(&buf, "%sID: %s\n", rs.indent, rs.ResolutionID)
fmt.Fprintf(&buf, "%sType: %s\n", rs.indent, rs.Type)
fmt.Fprintf(&buf, "%sExpiresAt: %d\n", rs.indent, rs.ExpiresAt)
fmt.Fprintf(&buf, "%sExpiresAt: %s\n", rs.indent, rs.ExpiresAt)
fmt.Fprintf(&buf, "%sBoard: %s\n", rs.indent, rs.Board)
fmt.Fprintf(&buf, "%sApprovals: %v\n", rs.indent, rs.Approved)
return buf.Bytes(), nil
Expand Down
7 changes: 4 additions & 3 deletions app/setup/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"strconv"
"strings"
"time"

"github.com/kwilteam/kwil-db/app/shared/display"
"github.com/kwilteam/kwil-db/config"
Expand Down Expand Up @@ -39,7 +40,7 @@ type genesisFlagConfig struct {
leader string
dbOwner string
maxBlockSize int64
joinExpiry int64
joinExpiry time.Duration
maxVotesPerTx int64
genesisState string
}
Expand Down Expand Up @@ -109,7 +110,7 @@ func bindGenesisFlags(cmd *cobra.Command, cfg *genesisFlagConfig) {
cmd.Flags().StringVar(&cfg.leader, "leader", "", "public key of the block proposer")
cmd.Flags().StringVar(&cfg.dbOwner, "db-owner", "", "owner of the database")
cmd.Flags().Int64Var(&cfg.maxBlockSize, "max-block-size", 0, "maximum block size")
cmd.Flags().Int64Var(&cfg.joinExpiry, "join-expiry", 0, "Number of blocks before a join proposal expires")
cmd.Flags().DurationVar(&cfg.joinExpiry, "join-expiry", 0, "Number of blocks before a join proposal expires")
cmd.Flags().Int64Var(&cfg.maxVotesPerTx, "max-votes-per-tx", 0, "Maximum votes per transaction")
cmd.Flags().StringVar(&cfg.genesisState, "genesis-snapshot", "", "path to genesis state snapshot file")
}
Expand Down Expand Up @@ -226,7 +227,7 @@ func mergeGenesisFlags(conf *config.GenesisConfig, cmd *cobra.Command, flagCfg *
}

if cmd.Flags().Changed("join-expiry") {
conf.JoinExpiry = flagCfg.joinExpiry
conf.JoinExpiry = types.Duration(flagCfg.joinExpiry)
}

if cmd.Flags().Changed("max-votes-per-tx") {
Expand Down
4 changes: 2 additions & 2 deletions app/shared/bind/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/kwilteam/kwil-db/config"
"github.com/kwilteam/kwil-db/core/log"
ktypes "github.com/kwilteam/kwil-db/core/types"
"github.com/kwilteam/kwil-db/node/pg"
"github.com/kwilteam/kwil-db/node/types"
)
Expand Down Expand Up @@ -107,7 +107,7 @@ func SetFlagsFromStructTags(fs *pflag.FlagSet, cfg interface{}, nameTag, descTag
case time.Duration:
fs.Duration(flagName, vt, desc)
return
case config.Duration:
case ktypes.Duration:
fs.Duration(flagName, time.Duration(vt), desc)
return
case types.HexBytes:
Expand Down
2 changes: 1 addition & 1 deletion app/validator/join-status.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (r *respValJoinStatus) MarshalText() ([]byte, error) {
var msg bytes.Buffer
msg.WriteString(fmt.Sprintf("Candidate: %s\n", r.Data.Candidate.String()))
msg.WriteString(fmt.Sprintf("Requested Power: %d\n", r.Data.Power))
msg.WriteString(fmt.Sprintf("Expiration Height: %d\n", r.Data.ExpiresAt))
msg.WriteString(fmt.Sprintf("Expiration Timestamp: %s\n", r.Data.ExpiresAt.String()))

msg.WriteString(fmt.Sprintf("%d Approvals Received (%d needed):\n", approved, needed))

Expand Down
11 changes: 7 additions & 4 deletions app/validator/join-status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package validator
import (
"encoding/json"
"testing"
"time"

"github.com/kwilteam/kwil-db/core/crypto"
"github.com/kwilteam/kwil-db/core/types"
Expand Down Expand Up @@ -59,6 +60,8 @@ func Test_respValJoinStatus_MarshalJSON(t *testing.T) {
}

func Test_respValJoinStatus_MarshalText(t *testing.T) {
now := time.Now()
nowStr := now.String()
tests := []struct {
name string
response respValJoinStatus
Expand All @@ -70,7 +73,7 @@ func Test_respValJoinStatus_MarshalText(t *testing.T) {
Data: &types.JoinRequest{
Candidate: &types.AccountID{Identifier: []byte{0x12, 0x34}, KeyType: crypto.KeyTypeSecp256k1},
Power: 1000,
ExpiresAt: 5000,
ExpiresAt: now,
Board: []*types.AccountID{
{Identifier: []byte{0xAB, 0xCD}, KeyType: crypto.KeyTypeSecp256k1},
{Identifier: []byte{0xEF, 0x12}, KeyType: crypto.KeyTypeSecp256k1},
Expand All @@ -79,23 +82,23 @@ func Test_respValJoinStatus_MarshalText(t *testing.T) {
Approved: []bool{true, true, true},
},
},
want: "Candidate: AccountID{identifier = 1234, keyType = secp256k1}\nRequested Power: 1000\nExpiration Height: 5000\n3 Approvals Received (2 needed):\nValidator AccountID{identifier = abcd, keyType = secp256k1}, approved\nValidator AccountID{identifier = ef12, keyType = secp256k1}, approved\nValidator AccountID{identifier = 5678, keyType = secp256k1}, approved\n",
want: "Candidate: AccountID{identifier = 1234, keyType = secp256k1}\nRequested Power: 1000\nExpiration Timestamp: " + nowStr + "\n3 Approvals Received (2 needed):\nValidator AccountID{identifier = abcd, keyType = secp256k1}, approved\nValidator AccountID{identifier = ef12, keyType = secp256k1}, approved\nValidator AccountID{identifier = 5678, keyType = secp256k1}, approved\n",
},
{
name: "mixed approvals",
response: respValJoinStatus{
Data: &types.JoinRequest{
Candidate: &types.AccountID{Identifier: []byte{0xFF}, KeyType: crypto.KeyTypeSecp256k1},
Power: 500,
ExpiresAt: 1000,
ExpiresAt: now,
Board: []*types.AccountID{
{Identifier: []byte{0x11, 0x22}, KeyType: crypto.KeyTypeSecp256k1},
{Identifier: []byte{0x33, 0x44}, KeyType: crypto.KeyTypeSecp256k1},
},
Approved: []bool{true, false},
},
},
want: "Candidate: AccountID{identifier = ff, keyType = secp256k1}\nRequested Power: 500\nExpiration Height: 1000\n1 Approvals Received (2 needed):\nValidator AccountID{identifier = 1122, keyType = secp256k1}, approved\nValidator AccountID{identifier = 3344, keyType = secp256k1}, not approved\n",
want: "Candidate: AccountID{identifier = ff, keyType = secp256k1}\nRequested Power: 500\nExpiration Timestamp: " + nowStr + "\n1 Approvals Received (2 needed):\nValidator AccountID{identifier = 1122, keyType = secp256k1}, approved\nValidator AccountID{identifier = 3344, keyType = secp256k1}, not approved\n",
},
}

Expand Down
4 changes: 2 additions & 2 deletions app/validator/list-join-requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func (r *respJoinList) MarshalText() ([]byte, error) {
msg.WriteString(fmt.Sprintf("Pending join requests (%d %s needed):\n", needed, approvalTerm))
msg.WriteString(" Candidate | Power | Approvals | Expiration\n")
msg.WriteString("------------------------------------------------------------------+-------+-----------+------------")
//ref spacing: 22cbbb666c26b2c1f42502df72c32de4d521138a1a2c96121d417a2f341a759c | 1 | 100 | 100
//ref spacing: 22cbbb666c26b2c1f42502df72c32de4d521138a1a2c96121d417a2f341a759c | 1 | 100 | 2025-01-21 11:01:49-0600 CST
for _, j := range r.Joins {
approvals := 0
for _, a := range j.Approved {
Expand All @@ -86,7 +86,7 @@ func (r *respJoinList) MarshalText() ([]byte, error) {
}
}

msg.WriteString(fmt.Sprintf("\n %s | % 5d | % 9d | %d", j.Candidate.String(), j.Power, approvals, j.ExpiresAt))
msg.WriteString(fmt.Sprintf("\n %s | % 5d | % 9d | %s", j.Candidate.String(), j.Power, approvals, j.ExpiresAt.String()))

}

Expand Down
38 changes: 19 additions & 19 deletions app/validator/list-join-requests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package validator
import (
"encoding/json"
"testing"
"time"

"github.com/kwilteam/kwil-db/core/crypto"
"github.com/kwilteam/kwil-db/core/types"
Expand All @@ -24,24 +25,22 @@ func Test_respJoinList_MarshalJSON(t *testing.T) {
Identifier: []byte{0x12, 0x34},
KeyType: crypto.KeyTypeEd25519,
},
Power: 100,
ExpiresAt: 900,
Board: []*types.AccountID{{Identifier: []byte{0xAB, 0xCD}, KeyType: crypto.KeyTypeSecp256k1}},
Approved: []bool{true},
Power: 100,
Board: []*types.AccountID{{Identifier: []byte{0xAB, 0xCD}, KeyType: crypto.KeyTypeSecp256k1}},
Approved: []bool{true},
},
{
Candidate: &types.AccountID{
Identifier: []byte{0x56, 0x78},
KeyType: crypto.KeyTypeSecp256k1,
},
Power: 200,
ExpiresAt: 1000,
Board: []*types.AccountID{{Identifier: []byte{0xEF, 0x12}, KeyType: crypto.KeyTypeSecp256k1}},
Approved: []bool{false},
Power: 200,
Board: []*types.AccountID{{Identifier: []byte{0xEF, 0x12}, KeyType: crypto.KeyTypeSecp256k1}},
Approved: []bool{false},
},
},
},
want: `[{"candidate":{"identifier":"1234","key_type":1},"power":100,"expires_at":900,"board":[{"identifier":"abcd","key_type":0}],"approved":[true]},{"candidate":{"identifier":"5678","key_type":0},"power":200,"expires_at":1000,"board":[{"identifier":"ef12","key_type":0}],"approved":[false]}]`,
want: `[{"candidate":{"identifier":"1234","key_type":1},"power":100,"expires_at": "0001-01-01T00:00:00Z","board":[{"identifier":"abcd","key_type":0}],"approved":[true]},{"candidate":{"identifier":"5678","key_type":0},"power":200,"expires_at":"0001-01-01T00:00:00Z","board":[{"identifier":"ef12","key_type":0}],"approved":[false]}]`,
},
{
name: "empty joins",
Expand All @@ -59,14 +58,13 @@ func Test_respJoinList_MarshalJSON(t *testing.T) {
Identifier: []byte{0x12, 0x34},
KeyType: crypto.KeyTypeEd25519,
},
Power: 150,
ExpiresAt: 1200,
Board: []*types.AccountID{{Identifier: []byte{0xAB, 0xCD}, KeyType: crypto.KeyTypeSecp256k1}},
Approved: []bool{true, false},
Power: 150,
Board: []*types.AccountID{{Identifier: []byte{0xAB, 0xCD}, KeyType: crypto.KeyTypeSecp256k1}},
Approved: []bool{true, false},
},
},
},
want: `[{"candidate":{"identifier":"1234","key_type":1},"power":150,"expires_at":1200,"board":[{"identifier":"abcd","key_type":0}],"approved":[true,false]}]`,
want: `[{"candidate":{"identifier":"1234","key_type":1},"power":150,"expires_at": "0001-01-01T00:00:00Z","board":[{"identifier":"abcd","key_type":0}],"approved":[true,false]}]`,
},
}

Expand All @@ -80,6 +78,8 @@ func Test_respJoinList_MarshalJSON(t *testing.T) {
}

func Test_respJoinList_MarshalText(t *testing.T) {
now := time.Now()
nowStr := now.String()
tests := []struct {
name string
response respJoinList
Expand All @@ -102,13 +102,13 @@ func Test_respJoinList_MarshalText(t *testing.T) {
KeyType: crypto.KeyTypeEd25519,
},
Power: 100,
ExpiresAt: 1000,
ExpiresAt: now,
Board: []*types.AccountID{{Identifier: []byte{0xAB}}},
Approved: []bool{true},
},
},
},
want: "Pending join requests (1 approval needed):\n Candidate | Power | Approvals | Expiration\n------------------------------------------------------------------+-------+-----------+------------\n AccountID{identifier = 1234, keyType = ed25519} | 100 | 1 | 1000",
want: "Pending join requests (1 approval needed):\n Candidate | Power | Approvals | Expiration\n------------------------------------------------------------------+-------+-----------+------------\n AccountID{identifier = 1234, keyType = ed25519} | 100 | 1 | " + nowStr,
},
{
name: "multiple approvals needed",
Expand All @@ -120,7 +120,7 @@ func Test_respJoinList_MarshalText(t *testing.T) {
KeyType: crypto.KeyTypeEd25519,
},
Power: 100,
ExpiresAt: 1000,
ExpiresAt: now,
Board: []*types.AccountID{
{Identifier: []byte{0xAB}},
{Identifier: []byte{0xCD}},
Expand All @@ -133,7 +133,7 @@ func Test_respJoinList_MarshalText(t *testing.T) {
Identifier: []byte{0x56, 0x78},
},
Power: 200,
ExpiresAt: 2000,
ExpiresAt: now,
Board: []*types.AccountID{
{Identifier: []byte{0xAB}},
{Identifier: []byte{0xCD}},
Expand All @@ -143,7 +143,7 @@ func Test_respJoinList_MarshalText(t *testing.T) {
},
},
},
want: "Pending join requests (2 approvals needed):\n Candidate | Power | Approvals | Expiration\n------------------------------------------------------------------+-------+-----------+------------\n AccountID{identifier = 1234, keyType = ed25519} | 100 | 2 | 1000\n AccountID{identifier = 5678, keyType = secp256k1} | 200 | 0 | 2000",
want: "Pending join requests (2 approvals needed):\n Candidate | Power | Approvals | Expiration\n------------------------------------------------------------------+-------+-----------+------------\n AccountID{identifier = 1234, keyType = ed25519} | 100 | 2 | " + nowStr + "\n AccountID{identifier = 5678, keyType = secp256k1} | 200 | 0 | " + nowStr,
},
}

Expand Down
Loading

0 comments on commit 1c3700e

Please sign in to comment.