def sign_deploy(private_key: str, term: str, phlo_price: int, phlo_limit: int, valid_after_block_number: int, timestamp: int, sig_algorithm: str) -> None: pri = PrivateKey.from_hex(private_key) signed_deploy = create_deploy_data(pri, term, phlo_price, phlo_limit, valid_after_block_number, timestamp) click.echo(signed_deploy.sig.hex())
def test_slash_GHOST_disobeyed(command_line_options: CommandLineOptions, random_generator: Random, docker_client: DockerClient) -> None: """ Slash a validator who doesn't follow GHOST. 1. bootstrap proposes a valid block B1 2. v2 proposes a valid block B2 3. v1 proposes a valid block B3 4. v1 proposes an invalid block B4 whose parent is B1 and send it to v2 5. v2 records invalid block B4 (InvalidParents) 6. v2 proposes a new block B5 which slashes v1 """ with three_nodes_network_with_node_client(command_line_options, random_generator, docker_client) as (context, bootstrap_node , validator1, validator2, client): contract = '/opt/docker/examples/tut-hello.rho' bootstrap_node.deploy(contract, BONDED_VALIDATOR_KEY_1) blockhash1 = bootstrap_node.propose() wait_for_node_sees_block(context, validator1, blockhash1) wait_for_node_sees_block(context, validator2, blockhash1) validator2.deploy(contract, BONDED_VALIDATOR_KEY_2) blockhash2 = validator2.propose() wait_for_node_sees_block(context, validator1, blockhash2) wait_for_node_sees_block(context, bootstrap_node, blockhash2) validator1.deploy(contract, BONDED_VALIDATOR_KEY_3) blockhash3 = validator1.propose() wait_for_node_sees_block(context, validator2, blockhash3) wait_for_node_sees_block(context, bootstrap_node, blockhash3) block_info1 = validator1.get_block(blockhash1) block_info3 = validator1.get_block(blockhash3) block_msg3 = client.block_request(block_info3.blockInfo.blockHash, validator1) invalid_block = BlockMessage() invalid_block.CopyFrom(block_msg3) invalid_block.header.ClearField("parentsHashList") # pylint: disable=maybe-no-member invalid_block.body.state.blockNumber = 2 # pylint: disable=maybe-no-member invalid_block.header.parentsHashList.append(bytes.fromhex(block_info1.blockInfo.blockHash)) # pylint: disable=maybe-no-member invalid_block.header.timestamp = int(time.time()*1000) # pylint: disable=maybe-no-member deploy_data = create_deploy_data(BONDED_VALIDATOR_KEY_2, Path("../rholang/examples/tut-hello.rho").read_text(), 1, 1000000) invalid_block.body.deploys[0].deploy.CopyFrom(deploy_data) # pylint: disable=maybe-no-member invalid_block_hash = gen_block_hash_from_block(invalid_block) invalid_block.sig = BONDED_VALIDATOR_KEY_1.sign_block_hash(invalid_block_hash) invalid_block.blockHash = invalid_block_hash client.send_block(invalid_block, validator2) record_invalid = re.compile("Recording invalid block {}... for InvalidParents".format(invalid_block_hash.hex()[:10])) wait_for_log_match(context, validator2, record_invalid) validator2.deploy(contract, BONDED_VALIDATOR_KEY_1) slashed_blockhash = validator2.propose() slashed_block_info = validator2.get_block(slashed_blockhash) bonds_validators = {b.validator: b.stake for b in slashed_block_info.blockInfo.bonds} assert bonds_validators[BONDED_VALIDATOR_KEY_1.get_public_key().to_hex()] == 0
def test_client_deploy(key: PrivateKey, terms: str, phlo_price: int, phlo_limit: int, valid_after_block_no: int, timestamp_millis: int) -> None: class DummyDeploySerivce(DeployServiceServicer): def doDeploy(self, request: DeployDataProto, context: grpc.ServicerContext) -> DeployResponse: return DeployResponse(result=request.sig.hex()) with deploy_service(DummyDeploySerivce()) as (server, port), \ RClient(TEST_HOST, port) as client: ret = client.deploy(key, terms, phlo_price, phlo_limit, valid_after_block_no, timestamp_millis) assert verify_deploy_data( key.get_public_key(), bytes.fromhex(ret), create_deploy_data(key, terms, phlo_price, phlo_limit, valid_after_block_no, timestamp_millis))
def test_slash_invalid_validator_approve_evil_block(command_line_options: CommandLineOptions, random_generator: Random, docker_client: DockerClient) -> None: """Slash a validator who doesn't slash invalid block 1.v1 proposes valid block 2.v1 creates another block with invalid parent block hash and sends it to v2 3.v2 creates block using v1's second block as parent hash (i.e. no slashing, another invalid block) and sends it to v3 4.v3 records invalid block (InvalidTransaction) from v2 5.v3 proposes block which slashes both v1 and v2 """ with three_nodes_network_with_node_client(command_line_options, random_generator, docker_client) as (context, validator3 , validator1, validator2, client): genesis_block = validator3.get_blocks(2)[0] contract = '/opt/docker/examples/tut-hello.rho' validator1.deploy(contract, BONDED_VALIDATOR_KEY_1) blockhash = validator1.propose() wait_for_node_sees_block(context, validator3, blockhash) wait_for_node_sees_block(context, validator2, blockhash) block_info = validator1.get_block(blockhash) block_msg = client.block_request(block_info.blockInfo.blockHash, validator1) evil_block_hash = generate_block_hash() # invalid block from validator1 invalid_block = BlockMessage() invalid_block.CopyFrom(block_msg) invalid_block.seqNum = block_msg.seqNum + 1 invalid_block.body.state.blockNumber = block_msg.body.state.blockNumber + 1 # pylint: disable=maybe-no-member invalid_block.blockHash = evil_block_hash invalid_block.header.timestamp = int(time.time()*1000) # pylint: disable=maybe-no-member invalid_block.sig = BONDED_VALIDATOR_KEY_1.sign_block_hash(evil_block_hash) invalid_block.header.ClearField("parentsHashList") # pylint: disable=maybe-no-member invalid_block.header.parentsHashList.append(bytes.fromhex(genesis_block.blockInfo.blockHash)) # pylint: disable=maybe-no-member invalid_block.ClearField("justifications") invalid_block.justifications.extend([ # pylint: disable=maybe-no-member Justification(validator=BONDED_VALIDATOR_KEY_1.get_public_key().to_bytes(), latestBlockHash=block_msg.blockHash), Justification(validator=BONDED_VALIDATOR_KEY_2.get_public_key().to_bytes(), latestBlockHash=bytes.fromhex(genesis_block.blockInfo.blockHash)), Justification(validator=BOOTSTRAP_NODE_KEY.get_public_key().to_bytes(), latestBlockHash=bytes.fromhex(genesis_block.blockInfo.blockHash)), ]) client.send_block(invalid_block, validator2) wait_for_node_sees_block(context, validator2, evil_block_hash.hex()) # block which is created by validator2 but not slashing validator1 block_not_slash_invalid_block = BlockMessage() block_not_slash_invalid_block.CopyFrom(block_msg) block_not_slash_invalid_block.seqNum = 1 block_not_slash_invalid_block.body.state.blockNumber = 1 # pylint: disable=maybe-no-member block_not_slash_invalid_block.sender = BONDED_VALIDATOR_KEY_2.get_public_key().to_bytes() block_not_slash_invalid_block.ClearField("justifications") block_not_slash_invalid_block.justifications.extend([ # pylint: disable=maybe-no-member Justification(validator=BONDED_VALIDATOR_KEY_1.get_public_key().to_bytes(), latestBlockHash=evil_block_hash), Justification(validator=BONDED_VALIDATOR_KEY_2.get_public_key().to_bytes(), latestBlockHash=bytes.fromhex(genesis_block.blockInfo.blockHash)), Justification(validator=BOOTSTRAP_NODE_KEY.get_public_key().to_bytes(), latestBlockHash=bytes.fromhex(genesis_block.blockInfo.blockHash)), ]) deploy_data = create_deploy_data(BONDED_VALIDATOR_KEY_2, Path("../rholang/examples/tut-hello.rho").read_text(), 1, 1000000) block_not_slash_invalid_block.body.deploys[0].deploy.CopyFrom(deploy_data) # pylint: disable=maybe-no-member block_not_slash_invalid_block.header.ClearField("parentsHashList") # pylint: disable=maybe-no-member block_not_slash_invalid_block.header.parentsHashList.append(bytes.fromhex(genesis_block.blockInfo.blockHash)) # pylint: disable=maybe-no-member block_not_slash_invalid_block.header.timestamp = int(time.time()*1000) # pylint: disable=maybe-no-member invalid_block_hash = gen_block_hash_from_block(block_not_slash_invalid_block) block_not_slash_invalid_block.sig = BONDED_VALIDATOR_KEY_2.sign_block_hash(invalid_block_hash) block_not_slash_invalid_block.blockHash = invalid_block_hash client.send_block(block_not_slash_invalid_block, validator3) # Because validator2 doesn't slash validator1's block while validator3 slash validator1's block, # hence there are some comm events lack of in validator3 which cause an invalid transaction record_invalid = re.compile("Recording invalid block {}... for InvalidTransaction".format(invalid_block_hash.hex()[:10])) wait_for_log_match(context, validator3, record_invalid) validator3.deploy(contract, BOOTSTRAP_NODE_KEY) slashed_blockhash = validator3.propose() slashed_block_info = validator3.get_block(slashed_blockhash) bonds_validators = {b.validator: b.stake for b in slashed_block_info.blockInfo.bonds} assert bonds_validators[BONDED_VALIDATOR_KEY_1.get_public_key().to_hex()] == 0 assert bonds_validators[BONDED_VALIDATOR_KEY_2.get_public_key().to_hex()] == 0
import time from rchain.crypto import PrivateKey, PublicKey from rchain.util import create_deploy_data, verify_deploy_data private_key = PrivateKey.generate() public_key = private_key.get_public_key() contract = "@0!(2)" deploy_data = create_deploy_data(key=private_key, term=contract, phlo_price=1, phlo_limit=100000, valid_after_block_no=10, timestamp_millis=int(time.time() * 1000)) assert verify_deploy_data(public_key, deploy_data.sig, deploy_data)