Added test for the draft of challenge

pull/507/head
szotov 2018-10-13 20:41:41 +03:00
parent 0e06d67252
commit 694eb7fff9
3 changed files with 155 additions and 4 deletions

View File

@ -50,8 +50,8 @@ contract ChallengeLibrary {
// copy public key except first byte
bytes memory preparedPublicKey = new bytes(64);
assembly {
let destination := add(mload(preparedPublicKey), 32)
let source := add(mload(_minerPublicKey), 33)
let destination := add(preparedPublicKey, 32)
let source := add(_minerPublicKey, 33)
mstore(destination, mload(source))
mstore(add(destination, 32), mload(add(source, 32)))
}
@ -74,8 +74,8 @@ contract ChallengeLibrary {
function check(
bytes _capsuleBytes,
bytes _cFragBytes
) public returns (bool) {
return false;
) public pure returns (bool) {
return _capsuleBytes.length == 100 && _cFragBytes.length == 100; // just for tests
}
}

View File

@ -0,0 +1,32 @@
import pytest
from web3.contract import Contract
ALGORITHM_SHA256 = 1
secret = (123456).to_bytes(32, byteorder='big')
@pytest.fixture()
def escrow(testerchain):
escrow, _ = testerchain.interface.deploy_contract('MinersEscrowStub')
return escrow
# @pytest.fixture(params=[False, True])
@pytest.fixture()
def challenge_contract(testerchain, escrow, request):
# creator, client, bad_node, node1, node2, node3, *everyone_else = testerchain.interface.w3.eth.accounts
contract, _ = testerchain.interface.deploy_contract('ChallengeLibrary', escrow.address, ALGORITHM_SHA256)
# if request.param:
# secret_hash = testerchain.interface.w3.sha3(secret)
# dispatcher, _ = testerchain.interface.deploy_contract('Dispatcher', contract.address, secret_hash)
#
# # Deploy second version of the government contract
# contract = testerchain.interface.w3.eth.contract(
# abi=contract.abi,
# address=dispatcher.address,
# ContractFactoryClass=Contract)
return contract

View File

@ -0,0 +1,119 @@
import os
import coincurve
import pytest
from eth_tester.exceptions import TransactionFailed
from eth_utils import to_canonical_address
from umbral.keys import UmbralPrivateKey
from cryptography.hazmat.backends.openssl import backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from umbral.signing import Signature
def sign_data(data, umbral_privkey):
umbral_pubkey_bytes = umbral_privkey.get_pubkey().to_bytes(is_compressed=False)
# Prepare hash of the data
hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
hash_ctx.update(data)
data_hash = hash_ctx.finalize()
# Sign data and calculate recoverable signature
cryptography_priv_key = umbral_privkey.to_cryptography_privkey()
signature_der_bytes = cryptography_priv_key.sign(data, ec.ECDSA(hashes.SHA256()))
signature = Signature.from_bytes(signature_der_bytes, der_encoded=True)
recoverable_signature = bytes(signature) + bytes([0])
pubkey_bytes = coincurve.PublicKey.from_signature_and_message(recoverable_signature, data_hash, hasher=None) \
.format(compressed=False)
if pubkey_bytes != umbral_pubkey_bytes:
recoverable_signature = bytes(signature) + bytes([1])
return data_hash, recoverable_signature
@pytest.mark.slow
def test_challenge_cfrag(testerchain, escrow, challenge_contract):
creator, miner, wrong_miner, *everyone_else = testerchain.interface.w3.eth.accounts
# Prepare one miner
tx = escrow.functions.setMinerInfo(miner, 1000).transact()
testerchain.wait_for_receipt(tx)
# Generate miner's Umbral key
umbral_privkey = UmbralPrivateKey.gen_key()
umbral_pubkey_bytes = umbral_privkey.get_pubkey().to_bytes(is_compressed=False)
# Sign Umbral public key using eth-key
hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
hash_ctx.update(umbral_pubkey_bytes)
umbral_pubkey_hash = hash_ctx.finalize()
provider = testerchain.interface.providers[0]
address = to_canonical_address(miner)
sig_key = provider.ethereum_tester.backend._key_lookup[address]
signed_umbral_pubkey = bytes(sig_key.sign_msg_hash(umbral_pubkey_hash))
# Prepare hash of the data
capsule = os.urandom(100)
cfrag = os.urandom(100)
data = capsule + cfrag
data_hash, recoverable_signature = sign_data(data, umbral_privkey)
# Challenge using good data
assert not challenge_contract.functions.challengedCFrags(data_hash).call()
tx = challenge_contract.functions.challengeCFrag(
capsule, cfrag, recoverable_signature, umbral_pubkey_bytes, signed_umbral_pubkey).transact()
testerchain.wait_for_receipt(tx)
# Hash of the data is saved and miner is not slashed
assert challenge_contract.functions.challengedCFrags(data_hash).call()
assert 1000 == escrow.functions.minerInfo(miner).call()
# Can't challenge miner with data that already was checked
with pytest.raises((TransactionFailed, ValueError)):
tx = challenge_contract.functions.challengeCFrag(
capsule, cfrag, recoverable_signature, umbral_pubkey_bytes, signed_umbral_pubkey).transact()
testerchain.wait_for_receipt(tx)
# Challenge using bad data
cfrag = os.urandom(101)
data = capsule + cfrag
data_hash, recoverable_signature = sign_data(data, umbral_privkey)
assert not challenge_contract.functions.challengedCFrags(data_hash).call()
tx = challenge_contract.functions.challengeCFrag(
capsule, cfrag, recoverable_signature, umbral_pubkey_bytes, signed_umbral_pubkey).transact()
testerchain.wait_for_receipt(tx)
# Hash of the data is saved and miner is slashed
assert challenge_contract.functions.challengedCFrags(data_hash).call()
assert 900 == escrow.functions.minerInfo(miner).call()
# Prepare hash of the data
capsule = os.urandom(100)
cfrag = os.urandom(100)
data = capsule + cfrag
data_hash, recoverable_signature = sign_data(data, umbral_privkey)
# Can't challenge miner using broken signatures
with pytest.raises((TransactionFailed, ValueError)):
tx = challenge_contract.functions.challengeCFrag(
capsule, cfrag, recoverable_signature[1:], umbral_pubkey_bytes, signed_umbral_pubkey).transact()
testerchain.wait_for_receipt(tx)
with pytest.raises((TransactionFailed, ValueError)):
tx = challenge_contract.functions.challengeCFrag(
capsule, cfrag, recoverable_signature, umbral_pubkey_bytes, signed_umbral_pubkey[1:]).transact()
testerchain.wait_for_receipt(tx)
# Can't use signature for another data
wrong_capsule = os.urandom(100)
with pytest.raises((TransactionFailed, ValueError)):
tx = challenge_contract.functions.challengeCFrag(
wrong_capsule, cfrag, recoverable_signature, umbral_pubkey_bytes, signed_umbral_pubkey).transact()
testerchain.wait_for_receipt(tx)
# Can't challenge nonexistent miner
address = to_canonical_address(wrong_miner)
sig_key = provider.ethereum_tester.backend._key_lookup[address]
signed_umbral_pubkey = bytes(sig_key.sign_msg_hash(umbral_pubkey_hash))
with pytest.raises((TransactionFailed, ValueError)):
tx = challenge_contract.functions.challengeCFrag(
capsule, cfrag, recoverable_signature, umbral_pubkey_bytes, signed_umbral_pubkey).transact()
testerchain.wait_for_receipt(tx)