diff --git a/byzcoin/README.md b/byzcoin/README.md index aa7639c71e..98bd674aef 100644 --- a/byzcoin/README.md +++ b/byzcoin/README.md @@ -77,34 +77,32 @@ Items 5 and 6 are the 'real' ByzCoin improvements as described in the [ByzCoin Paper](https://eprint.iacr.org/2017/406). ## Transaction collection and View Change - Transactions can be submitted by end-users to any conode in the roster for -the Skipchain that is holding the ByzCoin. - -At the beginning of each block creation, the leader launches a protocol to -contact all the followers in parallel and to request the outstanding -transactions they have. Once a follower answers this request, they are -counting on the leader to faithfully attempt to include their transaction. -There is no retry mechanism. + the Skipchain that is holding the ByzCoin. -With the collected transactions now in the leader, it runs them in order -to find out how many it can fit into 1/2 of a block interval. It then sends -the proposed block to the followers for them to validate. If there are transactions -remaining to be run, they will be prepended to the next collected set of -transactions when the next block interval expires. +Since `VersionRollup`, the transaction collection and view change request + have been changed. The leader does not request new transactions anymore, + rather the nodes send new transactions to the leader. The leader puts the + transactions in a queue and creates new blocks with as many transactions as + are found in the queue, respecting the maximum size of the block. This makes + the system more responsive if there are few transactions submitted to the + chain. A "view change" (change of leader) is needed when the leader stops performing -its duties correctly. Followers notice the need for a new leader if the leader -stops sending heartbeat messages within some time window or detect a malicious -behaviour (not implemented yet). - -The design is similar to the view-change protocol in PBFT (OSDI99). We keep the -view-change message that followers send when they detect an anomaly. But we -replace the new-view message with the ftcosi protocol and block creation. The -result of ftcosi is an aggregate signature of all the nodes that agree to -perform the view-change. The signature is included in the block which nodes -accept if the aggregate signature is correct. This technique enables nodes to -synchronise and replay blocks to compute the most up-to-date leader. + its duties correctly. If a node cannot send a transaction to the leader, it + asks all other nodes to send the transaction to the leader themselves. Every + node that couldn't send the transaction to the leader will start a view + change request. This will only detect stopped leaders, but not leaders who + censor certain transactions. + +The design of the view-change is similar to the view-change protocol in PBFT + (OSDI99). We keep the view-change message that followers send when they + detect an anomaly. But we replace the new-view message with the ftcosi + protocol and block creation. The result of ftcosi is an aggregate signature + of all the nodes that agree to perform the view-change. The signature is + included in the block which nodes accept if the aggregate signature is + correct. This technique enables nodes to synchronise and replay blocks to + compute the most up-to-date leader. # Structure Definitions diff --git a/byzcoin/proto.go b/byzcoin/proto.go index 94ef31900f..d629406196 100644 --- a/byzcoin/proto.go +++ b/byzcoin/proto.go @@ -71,7 +71,13 @@ type CreateGenesisBlock struct { Roster onet.Roster // GenesisDarc defines who is allowed to write to this skipchain. GenesisDarc darc.Darc - // BlockInterval in int64. + // BlockInterval in int64 as nanoseconds since the Unix Epoch. + // Before VersionRollup, + // this was the time the leader waited between a signed block and asking + // for new transactions. + // With VersionRollup, + // the BlockInterval is only used to calculate the maximum protocol + // timeouts and the time-window of acceptance of a new block. BlockInterval time.Duration // Maximum block size. Zero (or not present in protobuf) means use the default, 4 megs. // optional diff --git a/byzcoin/service.go b/byzcoin/service.go index 3c95da677a..b4de1ac3f6 100644 --- a/byzcoin/service.go +++ b/byzcoin/service.go @@ -369,8 +369,14 @@ func (s *Service) prepareTxResponse(req *AddTxRequest, tx *TxResult) (*AddTxResp // AddTransaction requests to apply a new transaction to the ledger. Note // that unlike other service APIs, it is *not* enough to only check for the -// error value to find out if an error has occured. The caller must also check +// error value to find out if an error has occurred. The caller must also check // AddTxResponse.Error even if the error return value is nil. +// Since VersionRollup, the leader failure detection has been moved in here. +// It is still only a stop-detection, and does not handle a censoring leader. +// If a ClientTransaction cannot be sent to the leader, +// it is sent to all other nodes. +// Every node that cannot send it to the leader will request a viewChange. +// If enough nodes fail to send it to the leader, a new leader will be elected. func (s *Service) AddTransaction(req *AddTxRequest) (*AddTxResponse, error) { s.closedMutex.Lock() if s.closed { @@ -2168,8 +2174,11 @@ func (s *Service) verifySkipBlock(newID []byte, newSB *skipchain.SkipBlock) bool } } + // The window here is calculated so that it can include some clock skew, + // the time for the signature, and processing time of the transactions. window := 4 * config.BlockInterval if window < minTimestampWindow { + // Set a minimum window when BlockInterval is very small during testing. window = minTimestampWindow } t1 := time.Now().Add(window) diff --git a/byzcoin/tx_pipeline.go b/byzcoin/tx_pipeline.go index 93c2678c9f..c1a58d3cbe 100644 --- a/byzcoin/tx_pipeline.go +++ b/byzcoin/tx_pipeline.go @@ -16,6 +16,9 @@ var maxTxHashes = 1000 // txPipeline gathers new ClientTransactions and VersionUpdate requests, // and queues them up to be proposed as new blocks. +// With VersionRollup and newer, +// the nodes send the ClientTransactions directly to the leader, +// which queues them up, and proposes them to the nodes for signing. type txPipeline struct { ctxChan chan ClientTransaction needUpgrade chan Version diff --git a/external/java/src/main/java/ch/epfl/dedis/lib/proto/ByzCoinProto.java b/external/java/src/main/java/ch/epfl/dedis/lib/proto/ByzCoinProto.java index c88d1814d6..d26ba87c76 100644 --- a/external/java/src/main/java/ch/epfl/dedis/lib/proto/ByzCoinProto.java +++ b/external/java/src/main/java/ch/epfl/dedis/lib/proto/ByzCoinProto.java @@ -2962,7 +2962,13 @@ public interface CreateGenesisBlockOrBuilder extends /** *
-     * BlockInterval in int64.
+     * BlockInterval in int64 as nanoseconds since the Unix Epoch.
+     * Before VersionRollup,
+     * this was the time the leader waited between a signed block and asking
+     * for new transactions.
+     * With VersionRollup,
+     * the BlockInterval is only used to calculate the maximum protocol
+     * timeouts and the time-window of acceptance of a new block.
      * 
* * required sint64 blockinterval = 4; @@ -2970,7 +2976,13 @@ public interface CreateGenesisBlockOrBuilder extends boolean hasBlockinterval(); /** *
-     * BlockInterval in int64.
+     * BlockInterval in int64 as nanoseconds since the Unix Epoch.
+     * Before VersionRollup,
+     * this was the time the leader waited between a signed block and asking
+     * for new transactions.
+     * With VersionRollup,
+     * the BlockInterval is only used to calculate the maximum protocol
+     * timeouts and the time-window of acceptance of a new block.
      * 
* * required sint64 blockinterval = 4; @@ -3259,7 +3271,13 @@ public ch.epfl.dedis.lib.proto.DarcProto.DarcOrBuilder getGenesisdarcOrBuilder() private long blockinterval_; /** *
-     * BlockInterval in int64.
+     * BlockInterval in int64 as nanoseconds since the Unix Epoch.
+     * Before VersionRollup,
+     * this was the time the leader waited between a signed block and asking
+     * for new transactions.
+     * With VersionRollup,
+     * the BlockInterval is only used to calculate the maximum protocol
+     * timeouts and the time-window of acceptance of a new block.
      * 
* * required sint64 blockinterval = 4; @@ -3269,7 +3287,13 @@ public boolean hasBlockinterval() { } /** *
-     * BlockInterval in int64.
+     * BlockInterval in int64 as nanoseconds since the Unix Epoch.
+     * Before VersionRollup,
+     * this was the time the leader waited between a signed block and asking
+     * for new transactions.
+     * With VersionRollup,
+     * the BlockInterval is only used to calculate the maximum protocol
+     * timeouts and the time-window of acceptance of a new block.
      * 
* * required sint64 blockinterval = 4; @@ -4223,7 +4247,13 @@ public ch.epfl.dedis.lib.proto.DarcProto.DarcOrBuilder getGenesisdarcOrBuilder() private long blockinterval_ ; /** *
-       * BlockInterval in int64.
+       * BlockInterval in int64 as nanoseconds since the Unix Epoch.
+       * Before VersionRollup,
+       * this was the time the leader waited between a signed block and asking
+       * for new transactions.
+       * With VersionRollup,
+       * the BlockInterval is only used to calculate the maximum protocol
+       * timeouts and the time-window of acceptance of a new block.
        * 
* * required sint64 blockinterval = 4; @@ -4233,7 +4263,13 @@ public boolean hasBlockinterval() { } /** *
-       * BlockInterval in int64.
+       * BlockInterval in int64 as nanoseconds since the Unix Epoch.
+       * Before VersionRollup,
+       * this was the time the leader waited between a signed block and asking
+       * for new transactions.
+       * With VersionRollup,
+       * the BlockInterval is only used to calculate the maximum protocol
+       * timeouts and the time-window of acceptance of a new block.
        * 
* * required sint64 blockinterval = 4; @@ -4243,7 +4279,13 @@ public long getBlockinterval() { } /** *
-       * BlockInterval in int64.
+       * BlockInterval in int64 as nanoseconds since the Unix Epoch.
+       * Before VersionRollup,
+       * this was the time the leader waited between a signed block and asking
+       * for new transactions.
+       * With VersionRollup,
+       * the BlockInterval is only used to calculate the maximum protocol
+       * timeouts and the time-window of acceptance of a new block.
        * 
* * required sint64 blockinterval = 4; @@ -4256,7 +4298,13 @@ public Builder setBlockinterval(long value) { } /** *
-       * BlockInterval in int64.
+       * BlockInterval in int64 as nanoseconds since the Unix Epoch.
+       * Before VersionRollup,
+       * this was the time the leader waited between a signed block and asking
+       * for new transactions.
+       * With VersionRollup,
+       * the BlockInterval is only used to calculate the maximum protocol
+       * timeouts and the time-window of acceptance of a new block.
        * 
* * required sint64 blockinterval = 4; diff --git a/external/proto/byzcoin.proto b/external/proto/byzcoin.proto index 0b1ceb6fb1..95ca5f6a0d 100644 --- a/external/proto/byzcoin.proto +++ b/external/proto/byzcoin.proto @@ -51,7 +51,13 @@ message CreateGenesisBlock { required onet.Roster roster = 2; // GenesisDarc defines who is allowed to write to this skipchain. required darc.Darc genesisdarc = 3; - // BlockInterval in int64. + // BlockInterval in int64 as nanoseconds since the Unix Epoch. + // Before VersionRollup, + // this was the time the leader waited between a signed block and asking + // for new transactions. + // With VersionRollup, + // the BlockInterval is only used to calculate the maximum protocol + // timeouts and the time-window of acceptance of a new block. required sint64 blockinterval = 4; // Maximum block size. Zero (or not present in protobuf) means use the default, 4 megs. optional sint32 maxblocksize = 5;