def _do_checkpoint(self, state, s, e, ledger_id, view_no, audit_txn_root_hash): # TODO CheckpointState/Checkpoint is not a namedtuple anymore # 1. check if updateNamedTuple works for the new message type # 2. choose another name # TODO: This is hack of hacks, should be removed when refactoring is complete if not self.is_master and audit_txn_root_hash is None: audit_txn_root_hash = "7RJ5bkAKRy2CCvarRij2jiHC16SVPjHcrpVdNsboiQGv" state = updateNamedTuple(state, digest=audit_txn_root_hash, digests=[]) self._checkpoint_state[s, e] = state self._logger.info( "{} sending Checkpoint {} view {} checkpointState digest {}. Ledger {} " "txn root hash {}. Committed state root hash {} Uncommitted state root hash {}" .format( self, (s, e), view_no, state.digest, ledger_id, self._db_manager.get_txn_root_hash(ledger_id), self._db_manager.get_state_root_hash(ledger_id, committed=True), self._db_manager.get_state_root_hash(ledger_id, committed=False))) checkpoint = Checkpoint(self._data.inst_id, view_no, s, e, state.digest) self._network.send(checkpoint) self._data.checkpoints.append(checkpoint)
def evilSendPrePrepareRequest(self, ppReq: PrePrepare): logger.debug( "EVIL: Creating pre-prepare message for request : {}".format( ppReq)) ppReq = updateNamedTuple(ppReq, digest=ppReq.digest + 'random') self.sentPrePrepares[self.viewNo, self.lastPrePrepareSeqNo] = ppReq self.send(ppReq, TPCStat.PrePrepareSent)
def _mark_checkpoint_stable(self, seqNo): previousCheckpoints = [] for (s, e), state in self._checkpoint_state.items(): if e == seqNo: # TODO CheckpointState/Checkpoint is not a namedtuple anymore # 1. check if updateNamedTuple works for the new message type # 2. choose another name state = updateNamedTuple(state, isStable=True) self._checkpoint_state[s, e] = state self._set_stable_checkpoint(e) break else: previousCheckpoints.append((s, e)) else: self._logger.debug("{} could not find {} in checkpoints".format( self, seqNo)) return self.set_watermarks(low_watermark=seqNo) for k in previousCheckpoints: self._logger.trace("{} removing previous checkpoint {}".format( self, k)) self._checkpoint_state.pop(k) self._remove_stashed_checkpoints(till_3pc_key=(self.view_no, seqNo)) self._bus.send( CheckpointStabilized(self._data.inst_id, (self.view_no, seqNo))) self._logger.info("{} marked stable checkpoint {}".format( self, (s, e)))
def badMethod(self, ledgerId): nonlocal malignedOnce pp = origMethod(ledgerId) if not malignedOnce: pp = updateNamedTuple(pp, digest=pp.digest + '123') malignedOnce = True return pp
def test_process_oredered(checkpoint_service, ordered, pre_prepare, tconf): with pytest.raises( LogicError, match="CheckpointService | Can't process Ordered msg because " "ppSeqNo {} not in preprepared".format(ordered.ppSeqNo)): checkpoint_service.process_ordered(ordered) checkpoint_service._data.preprepared.append( preprepare_to_batch_id(pre_prepare)) checkpoint_service.process_ordered(ordered) _check_checkpoint(checkpoint_service, 1, tconf.CHK_FREQ, pre_prepare) pre_prepare.ppSeqNo = tconf.CHK_FREQ ordered.ppSeqNo = pre_prepare.ppSeqNo checkpoint_service._data.preprepared.append( preprepare_to_batch_id(pre_prepare)) state = updateNamedTuple( checkpoint_service._checkpoint_state[1, tconf.CHK_FREQ], digests=["digest"] * (tconf.CHK_FREQ - 1)) checkpoint_service._checkpoint_state[1, tconf.CHK_FREQ] = state checkpoint_service.process_ordered(ordered) _check_checkpoint(checkpoint_service, 1, tconf.CHK_FREQ, pre_prepare, check_shared_data=True) pre_prepare.ppSeqNo += 1 ordered.ppSeqNo = pre_prepare.ppSeqNo checkpoint_service._data.preprepared.append( preprepare_to_batch_id(pre_prepare)) checkpoint_service.process_ordered(ordered) _check_checkpoint(checkpoint_service, tconf.CHK_FREQ + 1, tconf.CHK_FREQ * 2, pre_prepare)
def test_validate_prepare_wrong_audit_root(r, pre_prepare, prepare): r.processPrePrepare(pre_prepare, PRIMARY_NAME) prepare = updateNamedTuple(prepare, auditTxnRootHash=generate_state_root()) with pytest.raises(SuspiciousNode, match=str( Suspicions.PR_AUDIT_TXN_ROOT_HASH_WRONG.code)): r.validatePrepare(prepare, NON_PRIMARY_NAME)
def test_process_checkpoint(checkpoint_service, checkpoint, pre_prepare, tconf, ordered, validators, is_master): global caught_msg caught_msg = None checkpoint_service._bus.subscribe(Cleanup, catch_msg) quorum = checkpoint_service._data.quorums.checkpoint.value n = len(validators) assert quorum == n - getMaxFailures(n) - 1 senders = ["sender{}".format(i) for i in range(quorum + 1)] key = (1, tconf.CHK_FREQ) old_key = (-1, 0) checkpoint_service._stash_checkpoint( Checkpoint(1, checkpoint.viewNo, 1, 1, "1"), "frm") checkpoint_service._stash_checkpoint( Checkpoint(1, checkpoint.viewNo + 1, 1, 1, "1"), "frm") checkpoint_service._checkpoint_state[old_key] = CheckpointState( 1, ["digest"] * (tconf.CHK_FREQ - 1), None, {}, False) checkpoint_service._checkpoint_state[key] = CheckpointState( key[1] - 1, ["digest"] * (tconf.CHK_FREQ - 1), None, {}, False) pre_prepare.ppSeqNo = key[1] ordered.ppSeqNo = pre_prepare.ppSeqNo checkpoint_service._data.preprepared.append(pre_prepare) checkpoint_service.process_ordered(ordered) _check_checkpoint(checkpoint_service, key[0], key[1], pre_prepare, check_shared_data=True) state = updateNamedTuple(checkpoint_service._checkpoint_state[key], digest=checkpoint.digest) checkpoint_service._checkpoint_state[key] = state for sender in senders[:quorum - 1]: assert checkpoint_service.process_checkpoint(checkpoint, sender) assert checkpoint_service._checkpoint_state[key].receivedDigests[ sender] == checkpoint.digest assert not checkpoint_service._checkpoint_state[key].isStable # send the last checkpoint to stable it assert checkpoint_service.process_checkpoint(checkpoint, senders[quorum - 1]) assert checkpoint_service._checkpoint_state[key].isStable # check _remove_stashed_checkpoints() assert checkpoint.viewNo not in checkpoint_service._stashed_recvd_checkpoints assert checkpoint.viewNo + 1 in checkpoint_service._stashed_recvd_checkpoints # check watermarks assert checkpoint_service._data.low_watermark == checkpoint.seqNoEnd # check that a Cleanup msg has been sent assert isinstance(caught_msg, Cleanup) assert caught_msg.cleanup_till_3pc == (checkpoint.viewNo, checkpoint.seqNoEnd) # check that old checkpoint_states has been removed assert old_key not in checkpoint_service._checkpoint_state
def addToCheckpoint(self, ppSeqNo, digest): for (s, e) in self.checkpoints.keys(): if s <= ppSeqNo <= e: state = self.checkpoints[s, e] # type: CheckpointState state.digests.append(digest) state = updateNamedTuple(state, seqNo=ppSeqNo) self.checkpoints[s, e] = state break else: state = self._newCheckpointState(ppSeqNo, digest) s, e = ppSeqNo, ppSeqNo + self.config.CHK_FREQ if len(state.digests) == self.config.CHK_FREQ: state = updateNamedTuple(state, digest=serialize(state.digests), digests=[]) self.checkpoints[s, e] = state self.send(Checkpoint(self.instId, self.viewNo, ppSeqNo, state.digest))
def addToCheckpoint(self, ppSeqNo, digest): for (s, e) in self.checkpoints.keys(): if s <= ppSeqNo <= e: state = self.checkpoints[s, e] # type: CheckpointState state.digests.append(digest) state = updateNamedTuple(state, seqNo=ppSeqNo) self.checkpoints[s, e] = state break else: state = self._newCheckpointState(ppSeqNo, digest) s, e = ppSeqNo, ppSeqNo + self.config.CHK_FREQ if len(state.digests) == self.config.CHK_FREQ: state = updateNamedTuple(state, digest=serialize(state.digests), digests=[]) self.checkpoints[s, e] = state self.send( Checkpoint(self.instId, self.viewNo, ppSeqNo, state.digest))
def evilSendPrePrepareRequest(self, ppReq: PrePrepare): # reqDigest = ReqDigest(reqDigest.identifier, reqDigest.reqId, "random") # tm = time.time() # prePrepare = PrePrepare(self.instId, self.viewNo, # self.lastPrePrepareSeqNo+1, *reqDigest, tm) logger.debug( "EVIL: Creating pre-prepare message for request : {}".format( ppReq)) ppReq = updateNamedTuple(ppReq, digest=ppReq.digest + 'random') self.sentPrePrepares[self.viewNo, self.lastPrePrepareSeqNo] = ppReq self.send(ppReq, TPCStat.PrePrepareSent)
def test_validate_prepare_wrong_state_root(o, pre_prepare, prepare): handler = Mock() o._bus.subscribe(RaisedSuspicion, handler) o.process_preprepare(pre_prepare, PRIMARY_NAME) prepare = updateNamedTuple(prepare, stateRootHash=generate_state_root()) o._validate_prepare(prepare, NON_PRIMARY_NAME) check_suspicious( handler, RaisedSuspicion(inst_id=o._data.inst_id, ex=SuspiciousNode(NON_PRIMARY_NAME, Suspicions.PR_STATE_WRONG, prepare)))
def test_process_preprepare_on_old_view_pre_prepares_reply( external_bus, internal_bus, orderer, is_primary, initial_view_no, pre_prepares): # !!!SETUP!!! orderer._data.view_no = initial_view_no + 1 new_view = create_new_view( initial_view_no=initial_view_no, stable_cp=200, batches=create_batches_from_preprepares(pre_prepares)) orderer._data.new_view_votes.add_new_view(new_view, orderer._data.primary_name) orderer._data.prev_view_prepare_cert = new_view.batches[-1].pp_seq_no # !!!EXECUTE!!! rep = OldViewPrePrepareReply(0, [pp._asdict() for pp in pre_prepares]) orderer._network.process_incoming( rep, generateName("node1", orderer._data.inst_id)) # !!!CHECK!!! if not orderer.is_master: # no re-ordering is expected on non-master assert orderer._data.preprepared == [] assert orderer._data.prepared == [] return # check that PPs were added assert orderer._data.preprepared == [ BatchID(view_no=initial_view_no + 1, pp_view_no=pp.viewNo, pp_seq_no=pp.ppSeqNo, pp_digest=pp.digest) for pp in pre_prepares ] # check that sent_preprepares is updated in case of Primary and prePrepares in case of non-primary updated_prepares_collection = orderer.prePrepares if not is_primary else orderer.sent_preprepares non_updated_prepares_collection = orderer.sent_preprepares if not is_primary else orderer.prePrepares for pp in pre_prepares: new_pp = updateNamedTuple(pp, viewNo=initial_view_no + 1, originalViewNo=pp.viewNo) assert (initial_view_no + 1, new_pp.ppSeqNo) in updated_prepares_collection assert updated_prepares_collection[(initial_view_no + 1, new_pp.ppSeqNo)] == new_pp assert not non_updated_prepares_collection # check that Prepare is sent in case of non primary if not is_primary: check_prepares_sent(external_bus, pre_prepares, initial_view_no + 1) else: assert len(external_bus.sent_messages) == 0 # we don't have a quorum of Prepares yet assert orderer._data.prepared == []
def send_bad(self, msg, frm): if msg.msg_type == PREPREPARE: resp = self.replicas[msg.params['instId']].getPrePrepare( msg.params['viewNo'], msg.params['ppSeqNo']) resp = updateNamedTuple(resp, digest='11908ffq') self.sendToNodes(MessageRep(**{ f.MSG_TYPE.nm: msg.msg_type, f.PARAMS.nm: msg.params, f.MSG.nm: resp }), names=[frm, ]) else: return orig_method(msg, frm)
def test_validate_prepare_wrong_digest(o, pre_prepare, prepare): handler = Mock() o._bus.subscribe(RaisedSuspicion, handler) o.process_preprepare(pre_prepare, PRIMARY_NAME) prepare = updateNamedTuple(prepare, digest='fake_digest') o._validate_prepare(prepare, NON_PRIMARY_NAME) check_suspicious( handler, RaisedSuspicion(inst_id=o._data.inst_id, ex=SuspiciousNode(NON_PRIMARY_NAME, Suspicions.PR_DIGEST_WRONG, prepare)))
def add_to_pre_prepare(self, pre_prepare): if pre_prepare.ledgerId != TOKEN_LEDGER_ID and \ self.fees_tracker.fees_in_current_batch > 0: # Make sovtoken ledger and state root part of pre-prepare extra = { f.PLUGIN_FIELDS.nm: { FEES: { FEE_TXNS_IN_BATCH: self.fees_tracker.fees_in_current_batch, f.STATE_ROOT.nm: self.master_replica._ordering_service.get_state_root_hash( TOKEN_LEDGER_ID), f.TXN_ROOT.nm: self.master_replica._ordering_service.get_txn_root_hash( TOKEN_LEDGER_ID) } } } pre_prepare = updateNamedTuple(pre_prepare, **extra) return pre_prepare
def add_to_ordered(self, ordered, pre_prepare): if pre_prepare.ledgerId != TOKEN_LEDGER_ID and \ self._has_plugin_fields(pre_prepare): pre_prepare_fees_data = pre_prepare.plugin_fields.get(FEES, {}) if pre_prepare_fees_data: # the plugins_fields member created here is an exact copy of the one found in the pre_prepare msg extra = { f.PLUGIN_FIELDS.nm: { FEES: { FEE_TXNS_IN_BATCH: pre_prepare_fees_data.get( FEE_TXNS_IN_BATCH), f.STATE_ROOT.nm: pre_prepare_fees_data.get( f.STATE_ROOT.nm), f.TXN_ROOT.nm: pre_prepare_fees_data.get(f.TXN_ROOT.nm) } } } ordered = updateNamedTuple(ordered, **extra) return ordered
def add_to_prepare(self, prepare, pre_prepare): if pre_prepare.ledgerId != TOKEN_LEDGER_ID and \ self._has_plugin_fields(pre_prepare): # Make sovtoken ledger and state root part of pre-prepare pre_prepare_fees_data = pre_prepare.plugin_fields.get(FEES, {}) if pre_prepare_fees_data: extra = { f.PLUGIN_FIELDS.nm: { FEES: { FEE_TXNS_IN_BATCH: pre_prepare_fees_data.get( FEE_TXNS_IN_BATCH), f.STATE_ROOT.nm: pre_prepare_fees_data.get( f.STATE_ROOT.nm), f.TXN_ROOT.nm: pre_prepare_fees_data.get(f.TXN_ROOT.nm) } } } prepare = updateNamedTuple(prepare, **extra) return prepare
def markCheckPointStable(self, seqNo): previousCheckpoints = [] for (s, e), state in self.checkpoints.items(): if e == seqNo: state = updateNamedTuple(state, isStable=True) self.checkpoints[s, e] = state break else: previousCheckpoints.append((s, e)) else: logger.error("{} could not find {} in checkpoints". format(self, seqNo)) return self.h = seqNo for k in previousCheckpoints: logger.debug("{} removing previous checkpoint {}".format(self, k)) self.checkpoints.pop(k) self.gc(seqNo) logger.debug("{} marked stable checkpoint {}".format(self, (s, e))) self.processStashedMsgsForNewWaterMarks()
def markCheckPointStable(self, seqNo): previousCheckpoints = [] for (s, e), state in self.checkpoints.items(): if e == seqNo: state = updateNamedTuple(state, isStable=True) self.checkpoints[s, e] = state break else: previousCheckpoints.append((s, e)) else: logger.error("{} could not find {} in checkpoints".format( self, seqNo)) return self.h = seqNo for k in previousCheckpoints: logger.debug("{} removing previous checkpoint {}".format(self, k)) self.checkpoints.pop(k) self.gc(seqNo) logger.debug("{} marked stable checkpoint {}".format(self, (s, e))) self.processStashedMsgsForNewWaterMarks()
def _add_to_checkpoint(self, ppSeqNo, digest, ledger_id, view_no): for (s, e) in self._checkpoint_state.keys(): if s <= ppSeqNo <= e: state = self._checkpoint_state[s, e] # type: CheckpointState state.digests.append(digest) state = updateNamedTuple(state, seqNo=ppSeqNo) self._checkpoint_state[s, e] = state break else: s, e = ppSeqNo, math.ceil( ppSeqNo / self._config.CHK_FREQ) * self._config.CHK_FREQ self._logger.debug("{} adding new checkpoint state for {}".format( self, (s, e))) state = CheckpointState(ppSeqNo, [ digest, ], None, {}, False) self._checkpoint_state[s, e] = state if state.seqNo == e: if len(state.digests) == self._config.CHK_FREQ: self._do_checkpoint(state, s, e, ledger_id, view_no) self._process_stashed_checkpoints((s, e), view_no)
def _do_checkpoint(self, state, s, e, ledger_id, view_no): # TODO CheckpointState/Checkpoint is not a namedtuple anymore # 1. check if updateNamedTuple works for the new message type # 2. choose another name state = updateNamedTuple(state, digest=sha256( serialize_msg_for_signing( state.digests)).hexdigest(), digests=[]) self._checkpoint_state[s, e] = state self._logger.info( "{} sending Checkpoint {} view {} checkpointState digest {}. Ledger {} " "txn root hash {}. Committed state root hash {} Uncommitted state root hash {}" .format( self, (s, e), view_no, state.digest, ledger_id, self._db_manager.get_txn_root_hash(ledger_id), self._db_manager.get_state_root_hash(ledger_id, committed=True), self._db_manager.get_state_root_hash(ledger_id, committed=False))) checkpoint = Checkpoint(self._data.inst_id, view_no, s, e, state.digest) self._network.send(checkpoint) self._data.checkpoints.append(checkpoint)
def test_validate_prepare_wrong_txn_root(o, pre_prepare, prepare): o.process_preprepare(pre_prepare, PRIMARY_NAME) prepare = updateNamedTuple(prepare, txnRootHash=generate_state_root()) with pytest.raises(SuspiciousNode, match=str(Suspicions.PR_TXN_WRONG.code)): o.l_validatePrepare(prepare, NON_PRIMARY_NAME)
def evilSendPrePrepareRequest(self, ppReq: PrePrepare): logger.debug("EVIL: Creating pre-prepare message for request : {}". format(ppReq)) ppReq = updateNamedTuple(ppReq, digest=ppReq.digest + 'random') self.sentPrePrepares[self.viewNo, self.lastPrePrepareSeqNo] = ppReq self.send(ppReq, TPCStat.PrePrepareSent)
def test_process_preprepare_on_new_view_checkpoint_applied( internal_bus, external_bus, orderer, is_primary, all_ordered, initial_view_no, pre_prepares, stored_old_view_pre_prepares): # !!!SETUP!!! orderer._data.view_no = initial_view_no + 1 batches = create_batches_from_preprepares(pre_prepares) orderer._data.prev_view_prepare_cert = batches[-1].pp_seq_no new_view = create_new_view(initial_view_no=initial_view_no, stable_cp=200, batches=batches) # emulate that we received all PrePrepares before View Change orderer._update_old_view_preprepares(stored_old_view_pre_prepares) # emulate that we've already ordered the PrePrepares if all_ordered and stored_old_view_pre_prepares: orderer.last_ordered_3pc = (initial_view_no, stored_old_view_pre_prepares[-1].ppSeqNo) # !!!EXECUTE!!! # send NewViewCheckpointsApplied internal_bus.send( NewViewCheckpointsApplied(view_no=initial_view_no + 1, view_changes=new_view.viewChanges, checkpoint=new_view.checkpoint, batches=new_view.batches)) # !!!CHECK!!! if not orderer.is_master: # no re-ordering is expected on non-master assert orderer._data.preprepared == [] assert orderer._data.prepared == [] return # check that PPs were added stored_batch_ids = [ preprepare_to_batch_id(pp) for pp in stored_old_view_pre_prepares ] assert orderer._data.preprepared == [ BatchID(view_no=initial_view_no + 1, pp_view_no=initial_view_no, pp_seq_no=batch_id.pp_seq_no, pp_digest=batch_id.pp_digest) for batch_id in new_view.batches if batch_id in stored_batch_ids ] # check that sentPrePrepares is updated in case of Primary and prePrepares in case of non-primary updated_prepares_collection = orderer.prePrepares if not is_primary else orderer.sent_preprepares non_updated_prepares_collection = orderer.sent_preprepares if not is_primary else orderer.prePrepares for pp in stored_old_view_pre_prepares: new_pp = updateNamedTuple(pp, viewNo=initial_view_no + 1, originalViewNo=pp.viewNo) assert (initial_view_no + 1, new_pp.ppSeqNo) in updated_prepares_collection assert updated_prepares_collection[(initial_view_no + 1, new_pp.ppSeqNo)] == new_pp assert not non_updated_prepares_collection # check that Prepare is sent in case of non primary if not is_primary: check_prepares_sent(external_bus, stored_old_view_pre_prepares, initial_view_no + 1) else: # only MessageReqs are sent assert len(external_bus.sent_messages ) == len(pre_prepares) - len(stored_old_view_pre_prepares) # we don't have a quorum of Prepares yet assert orderer._data.prepared == [] # check that missing PrePrepares have been requested expected_requested_batches = [ batch_id for batch_id in new_view.batches if batch_id not in stored_batch_ids ] check_request_old_view_preprepares_sent(external_bus, expected_requested_batches)
def test_validate_prepare_wrong_digest(r, pre_prepare, prepare): r.processPrePrepare(pre_prepare, PRIMARY_NAME) prepare = updateNamedTuple(prepare, digest='fake_digest') with pytest.raises(SuspiciousNode, match=str(Suspicions.PR_DIGEST_WRONG.code)): r.validatePrepare(prepare, NON_PRIMARY_NAME)
def test_validate_prepare_wrong_state_root(r, pre_prepare, prepare): r.processPrePrepare(pre_prepare, PRIMARY_NAME) prepare = updateNamedTuple(prepare, stateRootHash=generate_state_root()) with pytest.raises(SuspiciousNode, match=str(Suspicions.PR_STATE_WRONG.code)): r.validatePrepare(prepare, NON_PRIMARY_NAME)