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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions blockproducer/branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"time"

pi "github.com/CovenantSQL/CovenantSQL/blockproducer/interfaces"
pl "github.com/CovenantSQL/CovenantSQL/blockproducer/limits"
"github.com/CovenantSQL/CovenantSQL/conf"
ca "github.com/CovenantSQL/CovenantSQL/crypto/asymmetric"
"github.com/CovenantSQL/CovenantSQL/crypto/hash"
"github.com/CovenantSQL/CovenantSQL/proto"
Expand Down Expand Up @@ -57,7 +57,7 @@ func newBranch(
}
// Apply new blocks to view and pool
for _, bn := range list {
if len(bn.block.Transactions) > pl.MaxTransactionsPerBlock {
if len(bn.block.Transactions) > conf.MaxTransactionsPerBlock {
return nil, ErrTooManyTransactionsInBlock
}

Expand Down Expand Up @@ -132,7 +132,7 @@ func (b *branch) applyBlock(n *blockNode) (br *branch, err error) {
}
var cpy = b.makeArena()

if len(n.block.Transactions) > pl.MaxTransactionsPerBlock {
if len(n.block.Transactions) > conf.MaxTransactionsPerBlock {
return nil, ErrTooManyTransactionsInBlock
}

Expand Down Expand Up @@ -185,7 +185,7 @@ func (b *branch) produceBlock(
cpy = b.makeArena()
txs = cpy.sortUnpackedTxs()
ierr error
packCount = pl.MaxTransactionsPerBlock
packCount = conf.MaxTransactionsPerBlock
)

if len(txs) < packCount {
Expand Down
71 changes: 40 additions & 31 deletions blockproducer/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"time"

pi "github.com/CovenantSQL/CovenantSQL/blockproducer/interfaces"
pl "github.com/CovenantSQL/CovenantSQL/blockproducer/limits"
"github.com/CovenantSQL/CovenantSQL/chainbus"
"github.com/CovenantSQL/CovenantSQL/conf"
"github.com/CovenantSQL/CovenantSQL/crypto"
Expand Down Expand Up @@ -188,7 +187,7 @@ func NewChainWithContext(ctx context.Context, cfg *Config) (c *Chain, err error)
return
}
if t = cfg.ConfirmThreshold; t <= 0.0 {
t = float64(2) / 3.0
t = conf.DefaultConfirmThreshold
}
if m = uint32(math.Ceil(float64(l)*t + 1)); m > l {
m = l
Expand Down Expand Up @@ -371,19 +370,29 @@ func (c *Chain) advanceNextHeight(now time.Time, d time.Duration) {

func (c *Chain) syncHeads() {
for {
var h = c.heightOfTime(c.now())
if c.getNextHeight() > h {
var (
now = c.now()
nowHeight uint32
)
if now.Before(c.genesisTime) {
log.WithFields(log.Fields{
"local": c.getLocalBPInfo(),
}).Info("now time is before genesis time, waiting for genesis")
break
}
if nowHeight = c.heightOfTime(c.now()); c.getNextHeight() > nowHeight {
break
}
for c.getNextHeight() <= h {
for c.getNextHeight() <= nowHeight {
// TODO(leventeliu): use the test mode flag to bypass the long-running synchronizing
// on startup by now, need better solution here.
if conf.GConf.StartupSyncHoles {
log.WithFields(log.Fields{
"local": c.getLocalBPInfo(),
"next_height": c.getNextHeight(),
"height": h,
"now_height": nowHeight,
}).Debug("synchronizing head blocks")
c.syncCurrentHead(c.ctx)
c.blockingSyncCurrentHead(c.ctx, conf.BPStartupRequiredReachableCount)
}
c.increaseNextHeight()
}
Expand Down Expand Up @@ -463,18 +472,18 @@ func (c *Chain) processAddTxReq(addTxReq *types.AddTxReq) {
le.WithError(err).Warn("failed to load base nonce of transaction account")
return
}
if nonce < base || nonce >= base+pl.MaxPendingTxsPerAccount {
if nonce < base || nonce >= base+conf.MaxPendingTxsPerAccount {
// TODO(leventeliu): should persist to somewhere for tx query?
le.WithFields(log.Fields{
"base_nonce": base,
"pending_limit": pl.MaxPendingTxsPerAccount,
"pending_limit": conf.MaxPendingTxsPerAccount,
}).Warn("invalid transaction nonce")
return
}

// Broadcast to other block producers
if ttl > pl.MaxTxBroadcastTTL {
ttl = pl.MaxTxBroadcastTTL
if ttl > conf.MaxTxBroadcastTTL {
ttl = conf.MaxTxBroadcastTTL
}
if ttl > 0 {
c.nonblockingBroadcastTx(ttl-1, tx)
Expand Down Expand Up @@ -509,7 +518,7 @@ func (c *Chain) mainCycle(ctx context.Context) {
select {
case <-timer.C:
// Try to fetch block at height `nextHeight-1` until enough peers are reachable
if err := c.blockingSyncCurrentHead(ctx); err != nil {
if err := c.blockingSyncCurrentHead(ctx, c.getRequiredConfirms()); err != nil {
log.WithError(err).Info("abort main cycle")
timer.Reset(0)
return
Expand Down Expand Up @@ -537,7 +546,7 @@ func (c *Chain) mainCycle(ctx context.Context) {
}
}

func (c *Chain) blockingSyncCurrentHead(ctx context.Context) (err error) {
func (c *Chain) blockingSyncCurrentHead(ctx context.Context, requiredReachable uint32) (err error) {
var (
ticker *time.Ticker
interval = 1 * time.Second
Expand All @@ -548,11 +557,11 @@ func (c *Chain) blockingSyncCurrentHead(ctx context.Context) (err error) {
ticker = time.NewTicker(interval)
defer ticker.Stop()
for {
if c.syncCurrentHead(ctx, requiredReachable) {
return
}
select {
case <-ticker.C:
if c.syncCurrentHead(ctx) {
return
}
case <-ctx.Done():
err = ctx.Err()
return
Expand All @@ -561,32 +570,26 @@ func (c *Chain) blockingSyncCurrentHead(ctx context.Context) (err error) {
}

// syncCurrentHead synchronizes a block at the current height of the local peer from the known
// remote peers. The return value `ok` indicates that there're at least `c.confirms-1` replies
// from these gossip calls.
func (c *Chain) syncCurrentHead(ctx context.Context) (ok bool) {
var h = c.getNextHeight() - 1
if c.head().height >= h {
// remote peers. The return value `ok` indicates that there're at least `requiredReachable-1`
// replies from these gossip calls.
func (c *Chain) syncCurrentHead(ctx context.Context, requiredReachable uint32) (ok bool) {
var currentHeight = c.getNextHeight() - 1
if c.head().height >= currentHeight {
ok = true
return
}

// Initiate blocking gossip calls to fetch block of the current height,
// with timeout of one tick.
var (
unreachable = c.blockingFetchBlock(ctx, h)

needConfirms, serversNum = func() (cf, sn uint32) {
c.RLock()
defer c.RUnlock()
cf, sn = c.confirms, c.localBPInfo.total
return
}()
unreachable = c.blockingFetchBlock(ctx, currentHeight)
serversNum = c.getLocalBPInfo().total
)

if ok = unreachable+needConfirms <= serversNum; !ok {
if ok = unreachable+requiredReachable <= serversNum; !ok {
log.WithFields(log.Fields{
"peer": c.getLocalBPInfo(),
"sync_head_height": h,
"sync_head_height": currentHeight,
"unreachable_count": unreachable,
}).Warn("one or more block producers are currently unreachable")
}
Expand Down Expand Up @@ -893,6 +896,12 @@ func (c *Chain) heightOfTime(t time.Time) uint32 {
return uint32(t.Sub(c.genesisTime) / c.period)
}

func (c *Chain) getRequiredConfirms() uint32 {
c.RLock()
defer c.RUnlock()
return c.confirms
}

func (c *Chain) getNextHeight() uint32 {
c.RLock()
defer c.RUnlock()
Expand Down
29 changes: 28 additions & 1 deletion blockproducer/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,32 @@ func TestChain(t *testing.T) {
Tick: time.Duration(300 * time.Millisecond),
}

Convey("A new chain running before genesis time should be waiting for genesis", func() {
config.Genesis.SignedHeader.Timestamp = time.Now().Add(24 * time.Hour)
err = genesis.PackAndSignBlock(testingPrivateKey)
So(err, ShouldBeNil)
chain, err = NewChain(config)
So(err, ShouldBeNil)

var sv = rpc.NewServer()
err = sv.InitRPCServer("localhost:0", testingPrivateKeyFile, []byte{})
So(err, ShouldBeNil)
defer sv.Stop()
chain.server = sv
chain.confirms = 1
chain.Start()
defer func() {
err = chain.Stop()
So(err, ShouldBeNil)
chain = nil
}()
time.Sleep(5 * chain.period)
var _, count, height, err = chain.fetchLastIrreversibleBlock()
So(err, ShouldBeNil)
So(count, ShouldEqual, 0)
So(height, ShouldEqual, 0)
})

chain, err = NewChain(config)
So(err, ShouldBeNil)
So(chain, ShouldNotBeNil)
Expand Down Expand Up @@ -345,7 +371,8 @@ func TestChain(t *testing.T) {
chain.confirms = 1
chain.Start()
defer func() {
chain.Stop()
err = chain.Stop()
So(err, ShouldBeNil)
chain = nil
}()
chain.addTx(&types.AddTxReq{TTL: 1, Tx: t1})
Expand Down
4 changes: 0 additions & 4 deletions blockproducer/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ import (
"github.com/CovenantSQL/CovenantSQL/types"
)

const (
blockVersion int32 = 0x01
)

// Config is the main chain configuration.
type Config struct {
Mode string
Expand Down
3 changes: 1 addition & 2 deletions blockproducer/limits/limits.go → conf/limits.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
* limitations under the License.
*/

// Package limits defines limits of the CovenantSQL system.
package limits
package conf

const (
// MaxTxBroadcastTTL defines the TTL limit of a AddTx request broadcasting within the
Expand Down
17 changes: 6 additions & 11 deletions conf/parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,12 @@

package conf

import "time"
// This parameters should be kept consistent in all BPs.
const (
DefaultConfirmThreshold = float64(2) / 3.0
)

// This parameters will not cause inconsistency within certain range.
const (
// BPPeriod is the block producer block produce period.
BPPeriod = 3 * time.Second
// BPTick is the block produce block fetch tick.
BPTick = 1 * time.Second
// SQLChainPeriod is the sqlchain block produce period.
SQLChainPeriod = 3 * time.Second
// SQLChainTick is the sqlchain block fetch tick.
SQLChainTick = 1 * time.Second
// SQLChainTTL is the sqlchain unack query billing ttl.
SQLChainTTL = 10
BPStartupRequiredReachableCount = 2 // NOTE: this includes myself
)