Пример #1
0
 class UnsignedChainId(HashableRLP):
     fields = (
         ('directive', big_endian_int),
         (
             'stakeMsg',
             List(
                 [  # list with the following members
                     Binary.fixed_length(
                         20, allow_empty=True),  # validatorAddress
                     List([Text()] * 5,
                          True),  # description is Text of 5 elements
                     List([big_endian_int],
                          True),  # new rate is in a list
                     big_endian_int,  # min self delegation
                     big_endian_int,  # max total delegation
                     Binary.fixed_length(
                         48, allow_empty=True),  # slot key to remove
                     Binary.fixed_length(
                         48, allow_empty=True),  # slot key to add
                 ],
                 True)),  # strictly these number of elements
         ('nonce', big_endian_int),
         ('gasPrice', big_endian_int),
         ('gasLimit', big_endian_int),
         ('chainId', big_endian_int),
     )
Пример #2
0
 class UnsignedChainId(HashableRLP):
     fields = (
         ('directive', big_endian_int),
         (
             'stakeMsg',
             List(
                 [  # list with the following members
                     Binary.fixed_length(
                         20, allow_empty=True),  # validatorAddress
                     List([Text()] * 5,
                          True),  # description is Text of 5 elements
                     List(
                         [List([big_endian_int], True)] * 3, True
                     ),  # commission rate is made up of 3 integers in an array [ [int1], [int2], [int3] ]
                     big_endian_int,  # min self delegation
                     big_endian_int,  # max total delegation
                     CountableList(
                         Binary.fixed_length(48, allow_empty=True)
                     ),  # bls-public-keys array of unspecified length, each key of 48
                     big_endian_int,  # amount
                 ],
                 True)),  # strictly these number of elements
         ('nonce', big_endian_int),
         ('gasPrice', big_endian_int),
         ('gasLimit', big_endian_int),
         ('chainId', big_endian_int),
     )
Пример #3
0
def test_list_sedes():
    l1 = List()
    l2 = List((big_endian_int, big_endian_int))
    l3 = List((l1, l2, [[[]]]))

    l1.serialize([])
    l2.serialize((2, 3))
    l3.serialize([[], [5, 6], [[[]]]])

    with pytest.raises(SerializationError):
        l1.serialize([[]])
    with pytest.raises(SerializationError):
        l1.serialize([5])

    for d in ([], [1, 2, 3], [1, [2, 3], 4]):
        with pytest.raises(SerializationError):
            l2.serialize(d)
    for d in ([], [[], [], [[[]]]], [[], [5, 6], [[]]]):
        with pytest.raises(SerializationError):
            l3.serialize(d)

    c = CountableList(big_endian_int)
    assert l1.deserialize(c.serialize([])) == ()
    for s in (c.serialize(l) for l in [[1], [1, 2, 3], range(30), (4, 3)]):
        with pytest.raises(DeserializationError):
            l1.deserialize(s)

    valid = [(1, 2), (3, 4), (9, 8)]
    for s, v in ((c.serialize(v), v) for v in valid):
        assert l2.deserialize(s) == v
    invalid = [[], [1], [1, 2, 3]]
    for s in (c.serialize(i) for i in invalid):
        with pytest.raises(DeserializationError):
            l2.deserialize(s)
Пример #4
0
    def serialize(cls, obj):
        sedes_list = List([
            big_endian_int,
            List([
                Binary.fixed_length(20),
                Binary.fixed_length(20), big_endian_int
            ])
        ])

        tx_elems = [obj.output_type, [obj.output_guard, obj.token, obj.amount]]

        tx_sedes = rlp.sedes.List(sedes_list)
        return tx_sedes.serialize(tx_elems)
Пример #5
0
class Body(rlp.Serializable):
    fields = (
        ('Source', text),
        ('Fee', text),
        ('SequenceID', big_endian_int),
        ('Operations', List((Operation, ), False)),
    )

    def serialize(self):
        cl = list()
        for i in self.as_dict()['Operations']:
            cl.append(i.__class__)

        class t(rlp.Serializable):
            fields = (
                ('Source', text),
                ('Fee', text),
                ('SequenceID', big_endian_int),
                ('Operations', List(tuple(cl), False)),
            )

        d = self.as_dict()
        tt = t(
            Source=d['Source'],
            Fee=d['Fee'],
            SequenceID=d['SequenceID'],
            Operations=d['Operations'],
        )

        return tt.serialize(tt)
Пример #6
0
 class t(rlp.Serializable):
     fields = (
         ('Source', text),
         ('Fee', text),
         ('SequenceID', big_endian_int),
         ('Operations', List(tuple(cl), False)),
     )
Пример #7
0
def test_list_of_serializable_decoding_rlp_caching(rlp_obj):
    rlp_obj_code = encode(rlp_obj, cache=False)
    L = [rlp_obj, rlp_obj]
    list_code = encode(L, cache=False)

    L2 = decode(list_code, sedes=List((type(rlp_obj), type(rlp_obj))), recursive_cache=True)
    assert L2[0]._cached_rlp == rlp_obj_code
    assert L2[1]._cached_rlp == rlp_obj_code
Пример #8
0
    def _get_serializer(cls):
        if cls._serializer is not None:
            return cls._serializer

        serializers = [serializer for _, serializer in cls.fields]
        serializer = serializers[0] if len(serializers) == 1 else List(
            serializers)

        cls._serializer = serializer

        return serializer
Пример #9
0
def test_list_sedes():
    l1 = List()
    l2 = List((big_endian_int, big_endian_int))
    l3 = List((l1, l2, [[[]]]))

    l1.serialize([])
    l2.serialize((2, 3))
    l3.serialize([[], [5, 6], [[[]]]])

    with pytest.raises(SerializationError):
        l1.serialize([[]])
    with pytest.raises(SerializationError):
        l1.serialize([5])

    for d in ([], [1, 2, 3], [1, [2, 3], 4]):
        with pytest.raises(SerializationError):
            l2.serialize(d)
    for d in ([], [[], [], [[[]]]], [[], [5, 6], [[]]]):
        with pytest.raises(SerializationError):
            l3.serialize(d)
Пример #10
0
def test_inference():
    obj_sedes_pairs = (
        (5, big_endian_int),
        (0, big_endian_int),
        (-1, None),
        (b'', binary),
        (b'asdf', binary),
        (b'\xe4\xf6\xfc\xea\xe2\xfb', binary),
        ([], List()),
        ([1, 2, 3], List((big_endian_int, ) * 3)),
        ([[], b'asdf'], List(([], binary))),
    )

    for obj, sedes in obj_sedes_pairs:
        if sedes is not None:
            inferred = infer_sedes(obj)
            assert inferred == sedes
            sedes.serialize(obj)
        else:
            with pytest.raises(TypeError):
                infer_sedes(obj)
Пример #11
0
 def header_event_watcher(log):
     header_logs, add_header_topic
     # print the last log and store the recent received one
     if log.topics[0] == add_header_topic:
         # print(log.data)
         header_logs.append(log.data)
         if len(header_logs) > 1:
             last_log = header_logs.pop(0)
             # [num, num, bytes32, bytes32, bytes32, address, bytes32, bytes32, bytes]
             # use sedes to prevent integer 0 from being decoded as b''
             sedes = List([utils.big_endian_int, utils.big_endian_int, utils.hash32, utils.hash32, utils.hash32, utils.address, utils.hash32, utils.hash32, binary])
             values = rlp.decode(last_log, sedes)
             print("add_header: shard_id={}, expected_period_number={}, header_hash={}, parent_header_hash={}".format(values[0], values[1], utils.sha3(last_log), values[3]))
Пример #12
0
 class UnsignedChainId(HashableRLP):
     fields = (
         ('directive', big_endian_int),
         ('stakeMsg',
          List([
              Binary.fixed_length(20, allow_empty=True),
              Binary.fixed_length(20, allow_empty=True), big_endian_int
          ], True)),
         ('nonce', big_endian_int),
         ('gasPrice', big_endian_int),
         ('gasLimit', big_endian_int),
         ('chainId', big_endian_int),
     )
Пример #13
0
def sign_apphash(apphash):
    sedes = CountableList(List([rlp.sedes.binary,
                                rlp.sedes.big_endian_int,
                                rlp.sedes.big_endian_int,
                                rlp.sedes.binary,
                                rlp.sedes.binary]))

    decoded = rlp.decode(bytes.fromhex(apphash), sedes)

    for i in decoded:
        data = list(i)
        data[2] = bool(data[2])
        msg_hash = w3.soliditySha3(['bytes32', 'uint256', 'bool', 'bytes', 'bytes'], data).hex()[2:]
        signed = utils.ecsign(bytes.fromhex(msg_hash), operator_normalize_key)
        tx = '1{0:0{1}X}{2:0{3}X}{4:0{5}X}{6:X}'.format(signed[1], 64,
                signed[2], 64, signed[0], 2, data[1])
        requests.get('http://localhost:26657/broadcast_tx_async?tx="{}"'.format(tx))
Пример #14
0
    def mine(self, number_of_blocks=1, coinbase=a0):
        self.cs.finalize(self.head_state, self.block)
        set_execution_results(self.head_state, self.block)
        self.block = Miner(self.block).mine(rounds=100, start_nonce=0)
        assert self.chain.add_block(self.block)
        b = self.block

        # Reorganize head collation
        collation = None
        # Check add_header_logs
        for item in self.add_header_logs:
            # [num, num, bytes32, bytes32, bytes32, address, bytes32, bytes32, bytes]
            # use sedes to prevent integer 0 from being decoded as b''
            sedes = List([
                utils.big_endian_int, utils.big_endian_int, utils.hash32,
                utils.hash32, utils.hash32, utils.address, utils.hash32,
                utils.hash32, binary
            ])
            values = rlp.decode(item, sedes)
            shard_id = values[0]
            if shard_id in self.chain.shard_id_list:
                collation_hash = sha3(item)
                collation = self.chain.shards[shard_id].get_collation(
                    collation_hash)
        self.chain.reorganize_head_collation(b, collation)
        # Clear logs
        self.add_header_logs = []

        for i in range(1, number_of_blocks):
            b, _ = make_head_candidate(self.chain,
                                       parent=b,
                                       timestamp=self.chain.state.timestamp +
                                       14,
                                       coinbase=coinbase)
            b = Miner(b).mine(rounds=100, start_nonce=0)
            assert self.chain.add_block(b)
            self.chain.reorganize_head_collation(b, None)

        self.change_head(b.header.hash, coinbase)
        return b
Пример #15
0
def decode_tx(tx):
    if tx.startswith('0x'):
        tx = tx[2:len(tx)]
    sedes = List([
        big_endian_int, big_endian_int, big_endian_int, binary, big_endian_int,
        binary, big_endian_int, binary, binary
    ])
    txc = codecs.decode(tx, "hex")
    keys = [
        'nonce', 'gasPrice', 'gasLimit', 'address', 'value', 'data', 'v', 'r',
        's'
    ]
    values = rlp.decode(txc, sedes)
    tx = {}
    for k, v in zip(keys, values):
        if k in ['address', 'r', 's']:
            tx[k] = binascii.hexlify(v).decode('ascii')
        elif k in ['data']:
            tx[k] = v.decode('ascii')
        else:
            tx[k] = v
    return tx
Пример #16
0
def L_S(t):  #(Tn, Tp, Tg, Tt, Tv, p) if v ∈ {27, 28}
    fs = [
        int(j["nounce"]),
        int(j["gasPrice"]),
        int(j["gasLimit"]),
        bytes.fromhex(j["to"]),
        int(j["value"]),
        bytes.fromhex(j["data"])
    ]

    list_sedes = List([
        big_endian_int, big_endian_int, big_endian_int, binary, big_endian_int,
        binary
    ])

    if "w" in j:
        fs += [int(j["w"]), int(j["r"]), int(j["s"])]
        list_sedes += [big_endian_int, big_endian_int, big_endian_int]
    else:
        fs += [int(j["chain_id"]), bytes.fromhex(""), bytes.fromhex("")]
        list_sedes += [big_endian_int, binary, binary]

    return rlp.encode(fs, list_sedes)
Пример #17
0
class NewKey(BaseMessage):

    content_sedes = List([
        big_endian_int, # sender index
        big_endian_int, # timestamp
        big_endian_int, # extra with sender type
        CountableList(raw), # [k(j, i)]
    ])

    payload_sedes = List([
        raw, # content
        raw, # auth(signature)
    ])

    def __init__(self,
                 sender:int, reqid:Reqid,
                 extra, hmac_keys):
        """Session key
        """
        super().__init__()

        self.sender = sender
        self.reqid = reqid
        self.extra = extra
        self.hmac_keys = hmac_keys

        self.content = None
        self.auth = None
        self.payload = None

        self.from_addr = None

    def verify(self, peer_principal):
        return peer_principal.verify(self.content_digest, self.auth)

    def __str__(self):
        return '{}:{}\n{}\n{}\n{}'.format(self.sender, self.reqid,
                                          self.extra, self.hmac_keys,
                                          self.auth)

    @property
    def content_digest(self):
        d = hashlib.sha256()
        d.update('{}'.format(self.sender).encode())
        d.update('{}'.format(self.reqid).encode())
        d.update('{}'.format(self.extra).encode())
        for k in self.hmac_keys:
            d.update(k)
        return d.digest()

    @classmethod
    def from_node(cls, node):

        hmac_keys = []
        for p in node.replica_principals:
            if p is node.principal:
                nonce = p.zero_hmac_nounce
            else:
                nonce = p.gen_inkey()

            hmac_keys.append(p.encrypt(nonce))

        extra = 0
        if node.type is 'Client':
            extra |= 1 << 4

        message = cls(node.sender, node.next_reqid(), extra, hmac_keys)
        message.content = rlp.encode([message.sender, message.reqid,
                                       message.extra, message.hmac_keys],
                                      cls.content_sedes)

        message.auth = node.principal.sign(message.content_digest)
        message.payload = rlp.encode([message.content, message.auth],
                                      cls.payload_sedes)
        return message

    @classmethod
    def from_payload(cls, payload, addr, _node):
        try:
            [content, auth] = rlp.decode(payload, cls.payload_sedes)

            [sender, reqid, extra, hmac_keys] = (
                rlp.decode(content, cls.content_sedes))

            message = cls(sender, reqid, extra, hmac_keys)
            message.content = content
            message.auth = auth
            message.payload = payload
            message.from_addr = addr

            return message
        except rlp.DecodingError as exc:
            raise ValueError('decoding error: {}'.format(exc))
Пример #18
0
class Prepare():

    content_sedes = List([
        big_endian_int, # view
        big_endian_int, # seqno
        big_endian_int, # extra
        big_endian_int, # sender
        raw, # consensus_digest of pre_prepare
    ])

    payload_sedes = List([
        raw, # content
        raw, # auth(signature)
    ])

    def __init__(self, view, seqno, extra,
                 sender, consensus_digest):
        self.view  = view
        self.seqno = seqno
        self.extra = extra
        self.sender = sender
        self.consensus_digest = consensus_digest

        self.content = None
        self.auth = None
        self.payload = None

    @property
    def use_signature(self):
        return True if self.extra & 2 else False

    @use_signature.setter
    def use_signature(self, val):
        if val:
            self.extra |= 2
        else:
            self.extra &= ~2

    @classmethod
    def from_backup(cls, backup, view, seqno,
                    use_signature:bool, consensus_digest):

        extra = 0
        if use_signature:
            extra |= 2

        return cls(view, seqno, extra,
                   backup.index, consensus_digest)

    @classmethod
    def from_payload(cls, payload, addr, _node):
        try:
            [content, auth] = rlp.decode(payload, cls.payload_sedes)
            [view, seqno, extra, sender, consensus_digest] = rlp.decode(
                content, cls.content_sedes)

            message = cls(view, seqno, extra, sender, consensus_digest)
            message.content = content
            message.auth = auth
            message.payload = payload

            return message
        except rlp.DecodingError as exc:
            raise ValueError('decoding error: {}'.format(exc))
Пример #19
0
    j = json.loads(ret.text)
    return j


if __name__ == '__main__':
    block = {}
    while True:
        latest = tendermint_latest_block()
        for blk in range(last_block + 1, latest + 1):
            print('blk', blk)
            tdm_block = get_tendermint_block(blk)
            apphash = tdm_block['result']['block_meta']['header']['app_hash']
            sedes = CountableList(
                List([
                    rlp.sedes.binary, rlp.sedes.big_endian_int,
                    rlp.sedes.big_endian_int, rlp.sedes.binary,
                    rlp.sedes.binary
                ]))
            d = rlp.decode(bytes.fromhex(apphash), sedes)
            for i in d:
                block[i[1]] = Block(i[0], i[1], bool(i[2]), i[3], i[4])
                plasma_latest_block = i[1]
            txs = tdm_block['result']['block']['data']['txs']
            for tx in txs:
                decoded_tx = base64.b64decode(tx).decode()
                if decoded_tx[0] == '1':
                    decoded_tx = decoded_tx[1:]
                    sig = decoded_tx[:130]
                    blkNum = int(decoded_tx[130:], 16)
                    block[blkNum].add_signature(sig)
                # block[i[1]].submit()
Пример #20
0
class Reply(BaseMessage):
    content_sedes = List([
        big_endian_int,  # view
        big_endian_int,  # timestamp(reqid)
        big_endian_int,  # extra
        big_endian_int,  # requestor index
        big_endian_int,  # replier index
        raw,  # result or digest
    ])

    payload_sedes = List([
        raw,  # content
        raw,  # auth(hmac)
    ])

    def __init__(self, view, reqid, extra, sender, replier, result: bytes):
        """
        :sender index id of replica sending this message
        :reqid reqid from the sender
        :node_type  always be replica
        """
        super().__init__()

        self.view = view
        self.reqid = reqid
        self.extra = extra
        self.sender = sender  # sender of request
        self.replier = replier
        self.result = result

        self.requestor = None  # principal

        self.content = None
        self.auth = None
        self.payload = None

    @property
    def reply_digest(self):
        d = hashlib.sha256()
        d.update(self.reply)
        return d.digest()

    @property
    def content_digest(self):
        d = hashlib.sha256()
        d.update('{}'.format(self.view).encode())
        d.update('{}'.format(self.reqid).encode())
        d.update('{}'.format(self.extra).encode())
        d.update('{}'.format(self.sender).encode())
        d.update('{}'.format(self.replier).encode())
        d.update('{}'.format(self.reply_digest).encode())
        return d.digest()

    @classmethod
    def from_node(cls, node, request, reply):

        extra = 0
        if node.type is 'Client':
            extra |= 1 << 4

        Message = cls(node.index, request.reqid, extra, node.view, reply)

        return message

    @classmethod
    def from_payload(cls, payload, addr, _node):
        try:
            [content, auth] = rlp.decode(payload, cls.payload_sedes)

            [sender, reqid, extra, view, reply_digest,
             reply] = (rlp.decode(content, cls.content_sedes))

            message = cls(sender, reqid, extra, view, reply)
            if message.reply_digest != reply_digest:
                raise ValueError('digest error')

            message.auth = auth
            message.from_addr = addr
            return message
        except rlp.DecodingErr as exc:
            raise ValueError('decoding error: {}'.format(exc))
Пример #21
0
import sys
import argparse
import hmac
import qrcode
import rlp
import subprocess
import numpy as np
from tqdm import tqdm
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
from rlp.sedes import big_endian_int, List
from rlp.exceptions import ListDeserializationError
from base64 import urlsafe_b64encode, urlsafe_b64decode

short_header_fmt = List([big_endian_int, big_endian_int])
header_fmt = List([big_endian_int, big_endian_int, big_endian_int])
_FONT_PATH = os.getenv('FONT_PATH', 'Arial.ttf')


def mkdirs_exists_ok(path):
    try:
        os.makedirs(path)
    except OSError:
        if not os.path.isdir(path):
            raise


def get_arg_parser():
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
Пример #22
0
    (
        (5, big_endian_int),
        (0, big_endian_int),
        (-1, None),
        (True, boolean),
        (False, boolean),
        (None, None),
        (b'', binary),
        (b'asdf', binary),
        (b'\xe4\xf6\xfc\xea\xe2\xfb', binary),
        ('', text),
        ('asdf', text),
        ('\xe4\xf6\xfc\xea\xe2\xfb', text),
        ('你好世界', text),
        ('\u4f60\u597d\u4e16\u754c', text),
        ([], List()),
        ([1, 2, 3], List((big_endian_int, ) * 3)),
        ([[], b'asdf'], List(([], binary))),
        ([1, 'asdf'], List((big_endian_int, text))),
    ),
)
def test_inference(value, expected):
    if expected is not None:
        inferred = infer_sedes(value)
        assert inferred == expected
        expected.serialize(value)
    else:
        with pytest.raises(TypeError):
            infer_sedes(value)

Пример #23
0
class RLPType2(Serializable):
    fields = [
        ('field2_1', RLPType1),
        ('field2_2', List((RLPType1, RLPType1))),
    ]
Пример #24
0
class RLPType1(Serializable):
    fields = [
        ('field1', big_endian_int),
        ('field2', binary),
        ('field3', List((big_endian_int, binary)))
    ]
Пример #25
0
            tuple(self.items()),
        ))

    def __repr__(self) -> str:
        base64_rlp = base64.urlsafe_b64encode(rlp.encode(self))
        unpadded_base64_rlp = base64_rlp.rstrip(b"=")
        return "".join((
            ENR_REPR_PREFIX,
            unpadded_base64_rlp.decode("ASCII"),
        ))


IDENTITY_SCHEME_ENR_KEY = b"id"

ENR_KEY_SEDES_MAPPING = {
    b"id": binary,
    b"secp256k1": Binary.fixed_length(33),
    b"ip": Binary.fixed_length(IP_V4_SIZE),
    b"tcp": big_endian_int,
    b"udp": big_endian_int,
    b"ip6": Binary.fixed_length(IP_V6_SIZE),
    b"tcp6": big_endian_int,
    b"udp6": big_endian_int,
    # For now this key is used only for ForkIDs (https://eips.ethereum.org/EIPS/eip-2124) but it
    # is represented as a List because more stuff (e.g. network-id) may be added in the future.
    b"eth": List([ForkID]),
}

# Must use raw for values with an unknown key as they may be lists or individual values.
FALLBACK_ENR_VALUE_SEDES = raw
Пример #26
0
                        (is_bytes, identity),
                    )),
                    "storageKeys": apply_formatter_to_array(hexstr_if_str(to_int))
                }
            ),
        ),
        'maxPriorityFeePerGas': hexstr_if_str(to_int),
        'maxFeePerGas': hexstr_if_str(to_int),
    },
)

# Define typed transaction common sedes.
# [[{20 bytes}, [{32 bytes}...]]...], where ... means “zero or more of the thing to the left”.
access_list_sede_type = CountableList(
    List([
        Binary.fixed_length(20, allow_empty=False),
        CountableList(BigEndianInt(32)),
    ]),
)


class _TypedTransactionImplementation(ABC):
    """
    Abstract class that every typed transaction must implement.
    Should not be imported or used by clients of the library.
    """
    @abstractmethod
    def hash(self) -> bytes:
        pass

    @abstractmethod
    def payload(self) -> bytes:
Пример #27
0
class PrePrepare(BaseMessage):

    content_sedes = List([
        big_endian_int, # view
        big_endian_int, # seqno
        big_endian_int, # extra
        # requests, with sha256(b'\x12...') or payload('\x60...')
        CountableList(raw),
        raw, # non_det_choices
    ])

    payload_sedes = List([
        raw, # content
        raw, # auth(signature)
    ])

    def __init__(self, view, seqno, extra,
                 requests, non_det_choices):
        super().__init__()
        
        self.view = view
        self.seqno = seqno
        self.extra = extra
        self.requests = requests
        self.non_det_choices = non_det_choices

        self.content = None
        self.auth = None
        self.payload = None

    @property
    def use_signature(self):
        return True if self.extra & 2 else False

    @use_signature.setter
    def use_signature(self, val):
        if val:
            self.extra |= 2
        else:
            self.extra &= ~2

    @property
    def consensus_digest(self):
        """Used to make sure that primary did NOT tamper the requests
        including all request.consensus_digest and non_det_choices
        """
        d = hashlib.sha256()
        for r in self.requests:
            d.update(r.consensus_digest)
        d.update(self.non_det_choices)

        return d.digest()

    @property
    def content_digest(self):
        d = hashlib.sha256()
        d.update('{}'.format(self.view).encode())
        d.update('{}'.format(self.seqno).encode())
        d.update('{}'.format(self.extra).encode())
        for r in self.requests:
            d.update(r.content_digest)
        d.update(self.non_det_choices)
        return d.digest()

    @property
    def is_requests_verified(self, node):
        count = 0
        for r in self.requests:
            if r.verified:
                count += 1
        return count == len(self.requests)

    def gen_payload(self, primary):
        raw_requests = [r.payload_in_pre_prepare for r in self.requests]
        self.content = rlp.encode([self.view, self.seqno,
                                   self.extra, raw_requests,
                                   self.non_det_choices],
                                  cls.content_sedes)

        self.authenticate(primary)
        self.payload = rlp.encode([self,content, self.raw_auth],
                                  cls.payload_sedes)

    @classmethod
    def from_primary(cls, primary, use_signature:bool):
        extra = 0
        if use_signature:
            extra |= 2

        non_det_choices = b'' # TODO: non deterministic choices
        message = cls(primary.view, primary.seqno, extra,
                      None, non_det_choices)

        requests = [] # request payload
        for rs in primary.rw_requests:
            if rs and rs[-1].pre_prepare_candidate:
                r = rs.pop(-1)
                requests.append(r)

            if len(requests) >= conf.request_in_pre_prepare:
                break

        message.requests = requests
        message.gen_payload(primary)

        return message

    @classmethod
    def from_payload(cls, payload, addr, node):
        try:
            [content, auth] = rlp.decode(payload, cls.payload_sedes)
            [view, seqno, extra, requests, non_det_choices] = rlp.decode(
                content, cls.content_sedes)

            for i, r in enumerate(requests):
                requests[i] = Request.from_payload(r, addr, node)
            
            message = cls(view, seqno, extra, requests, non_det_choices)

            message.content = content
            if message.use_signature:
                message.auth = auth
            else:
                message.auth = rlp.decode(auth, cls.authenticators_sedes)
            message.payload = payload
            message.from_addr = addr

            return message
        except rlp.DecodingError as exc:
            raise ValueError('decoding error: {}'.format(exc))
Пример #28
0
 class Test2(Serializable):
     fields = (
         ('field1', Test1),
         ('field2', List((Test1, Test1))),
     )
Пример #29
0
 class Test1(Serializable):
     fields = (('field1', big_endian_int), ('field2', binary),
               ('field3', List((big_endian_int, binary))))
Пример #30
0
class Request(BaseMessage):

    content_sedes = List([
        big_endian_int, # sender index
        big_endian_int, # timestamp(reqid)
        big_endian_int, # extra bitmap
        big_endian_int, # full replier
        raw, # command or command_digest
    ])

    payload_sedes = List([
        raw, # content
        raw, # auth(authenticators or signature)
             # maybe empty(b'') if content contains command_digest
    ])

    def __init__(self, sender:int, reqid:Reqid, extra:int,
                 full_replier:int, command:bytes):
        """
        :extra bit 1: 0 readwrite,          1 readonly
               bit 2: 0 authenticators,     1 signature
               bit 5: 0 send from replica   1 send from client
               bit 6: 0 full replier,       1 reply from all
                        this flag is used for there is no -1 in rlp encoding
        :command set by users
        :auth bytes(signature) or [hmac_sha256...](authenticators)
        :full_replier ignored if extra & 1 << 5 is set (reply from all)
        """
        super().__init__();

        self.sender = sender
        self.reqid = reqid
        self.extra = extra
        self.full_replier = full_replier
        self.reply_will_full = False

        self.command = command
        self._command_digest = None

        self.content = None
        self.auth = None
        self.payload = None

        self.from_addr = None

    @property
    def readonly(self):
        return True if self.extra & 1 else False

    @readonly.setter
    def readonly(self, val):
        if val:
            self.extra |= 1
        else:
            self.extra &= ~1

    @property
    def use_signature(self):
        return True if self.extra & 2 else False

    @use_signature.setter
    def use_signature(self, val):
        if val:
            self.extra |= 2
        else:
            self.extra &= ~2

    @property
    def reply_from_all(self):
        return True if self.extra & 1 << 5 else False

    @reply_from_all.setter
    def reply_from_all(self, val):
        if val:
            self.extra |= 1 << 5
        else:
            self.extra &= ~(1 << 5)

    @property
    def command_digest(self):
        """compute digest for command"""
        if self.command:
            d = hashlib.sha256()
            # dx: i am going to use the data instead of hahs
            # so I am commenting them out.
            # d.update('{}'.format(self.sender).encode())    # useless
            # d.update('{}'.format(self.reqid).encode())     # useless
            d.update(self.command)                           # useful
            return d.digest()

        return self._command_digest

    @property.setter
    def command_digest(self, new_command_digest):
        if not self.command:
            self._command_digest = new_command_digest

    @property
    def consensus_digest(self):
        d = hashlib.sha256()
        if self.sender_type is 'Client':
            d.update('{}'.format(1).encode())
        else:
            d.update('{}'.format(0).encode())
        d.update('{}'.format(self.sender).encode())
        d.update('{}'.format(self.reqid).encode())
        d.update(self.command_digest)
        return d.digest()

    @property
    def content_digest(self):
        d = hashlib.sha256()
        if self.sender_type is 'Client':
            d.update('{}'.format(1).encode())
        else:
            d.update('{}'.format(0).encode())
        d.update('{}'.format(self.sender).encode())
        d.update('{}'.format(self.reqid).encode())
        d.update('{}'.format(self.extra).encode())
        d.update('{}'.format(self.full_replier).encode())
        d.update(self.command_digest) # includes command and len(command)
        return d.digest()

    def gen_payload(self, node):
        self.content = rlp.encode([
            self.sender, self.reqid, self.extra,
            self.full_replier, self.command,
        ], self.content_sedes)

        self.authenticate(node)
        self.payload = rlp.encode([self.content, self.raw_auth],
                                  self.payload_sedes)

    def change_by_primary(self, request, primary):
        assert request.verified and self.verified

        changed = False
        if self.extra != request.extra:
            self.extra = request.extra
            changed = True
        if self.full_replier != request.full_replier:
            self.full_replier = request.full_replier
            changed = True
        if self.auth != request.auth:
            self.auth = request.auth
            changed = True # re-authenticated

        self.reply_with_full = (self.reply_with_full
                                or self.reply_from_all
                                or self.full_replier == primary.index)

        if changed:
            self.gen_payload()

       return changed

    def change_by_backup(self, request, backup):
        assert request.verified # only allow verified request

        if not self.command:
            self.command = request.command

        changed = False
        if self.extra != request.extra:
            self.extra = request.extra
            changed = True
        if self.full_replier != request.full_replier:
            self.full_replier = request.full_replier
            changed = True
        if self.auth != request.auth:
            self.auth = request.auth
            changed = True # re-authenticated

        self.reply_with_full = (self.reply_with_full
                                or self.reply_from_all
                                or self.full_replier == backup.index)

        self.verified = True # if was False, updated by verified reuqest

        if changed:
            self.gen_payload()

        return changed

    def verify(self, node, peer_principal):
        pp = peer_principal

        if self.verified or not self.auth:
            pass # already verified or no auth to verify
        elif self.use_signature:
            self.verified = pp.verify(self.content_digest, self.auth)
        else:
            if len(node.replica_principals) != len(self.auth):
                self.verifed = False
            else:
                # for request, we use 'out' key for the authentication
                assert pp.index == self.sender
                self.verified = (pp.gen_hmac('out', self.content_digest)
                                 == self.auth[self.sender])

        return self.verified

    @property
    def payload_in_pre_prepare(self):
        if len(self.command) <= conf.pre_prepare_big_request_thresh:
            return self.payload

        content = rlp.encode([
            self.sender, self.reqid, self.extra,
            self.full_replier, self.command_digest
        ], message.content_sedes)

        payload = rlp.encode([content, b''], message.payload_sedes)

        return payload


    @classmethod
    def from_client(cls, node,
                  readonly:bool, use_signature:bool, reply_from_all:bool,
                  full_replier:int, command:bytes):

        extra = 0
        if readonly:
            extra |= 1
        if use_signature:
            extra |= 2
        if node.type is 'Client':
            extra |= 1 << 4
        if reply_from_all:
            extra |= 1 << 5

        message = cls(node.sender, node.next_reqid(), extra,
                      full_replier, command)
        message.gen_payload()

        return message

    @classmethod
    def from_payload(cls, payload, addr, node):
        try:
            [content, auth] = rlp.decode(payload, cls.payload_sedes)
            [sender, reqid, extra, full_replier, extra, command] = (
                rlp.decode(content, cls.content_sedes))

            if not auth:
                # this should be a request inside of a pre_prepare
                # it has no auth attached, get the full request form client
                message = cls(sender, reqid, extra, full_replier, None)
                message.command_digest = command
            else:
                # full request
                message = cls(sender, reqid, extra, full_replier, command)
                if message.use_signature:
                    message.auth = auth
                else:
                    message.auth = rlp.decode(auth, cls.authenticators_sedes)

            message.content = content
            message.payload = payload
            
            if (message.reply_from_all
                or message.full_replier == node.index):
                message.reply_with_full = True

            message.from_addr = addr

            return message
        except rlp.DecodingError as exc:
            raise ValueError('decoding error: {}'.format(exc))