Example #1
0
class Tx(js.Entity, bs.Entity):
    type = "tx"
    fields = {
        "version": js.Int,
        "inputs": js.List(TxInput),
        "outputs": js.List(TxOutput),
        "locktime": js.Int,
    }
    bfields = [
        ("version", bs.structfmt("<I")),
        ("inputs", bs.VarList(TxInput)),
        ("outputs", bs.VarList(TxOutput)),
        ("locktime", bs.structfmt("<I")),
    ]

    @cachedproperty
    def hash(self):
        return doublesha(self.tobinary())

    @property
    def coinbase(self):
        return len(
            self.inputs
        ) == 1 and self.inputs[0].outpoint.tx == nullhash and self.inputs[
            0].outpoint.index == 0xffffffff

    def __repr__(self):
        return "<Tx %s, %d inputs, %d outputs, coinbase: %s>" % (h2h(
            self.hash), len(self.inputs), len(self.outputs), str(
                self.coinbase))
Example #2
0
class Version(js.Entity, bs.Entity):
    type = "version"
    fields = {
        "type": js.Str,
        "version": js.Int,
        "services": js.Int,
        "time": js.Int,
        "reciever": Address,
        "sender": Address,
        "nonce": js.Int,
        "subverinfo": js.Str,
        "finalblock": js.Int
    }
    bfields = [
        ("version", bs.structfmt("<I")),
        ("services", bs.structfmt("<Q")),
        ("time", bs.structfmt("<Q")),
        ("reciever", Address),
        ("sender", Address),
        ("nonce", bs.structfmt("<Q")),
        ("subverinfo", bs.Str),
        ("finalblock", bs.structfmt("<I")),
    ]

    @constructor
    def make(self, reciever):
        self.version = status.protocolversion
        self.services = status.services
        self.time = int(time.time())
        self.sender = status.localaddress
        self.reciever = reciever
        self.nonce = status.nonce
        self.subverinfo = ""
        self.finalblock = status.currentblock
Example #3
0
class BlockAux(js.Entity, bs.Entity):
    fields = {
        "block": Block,
        "txs": js.List(js.Hash),
        "number": js.Int,
        "totaldiff": js.Int,
        "invalid": js.Bool,
        "mainchain": js.Bool,
        "chained": js.Bool,
        "succ": js.Hash,
    }
    bfields = [
        ("block", Block),
        ("txs", bs.VarList(bs.Hash)),
        ("number", bs.structfmt("<I")),
        ("totaldiff", bs.structfmt("<Q")),
        ("invalid", bs.structfmt("<?")),
        ("mainchain", bs.structfmt("<?")),
        ("chained", bs.structfmt("<?")),
        ("succ", bs.Hash),
    ]

    @constructor
    def make(self, block):
        self.block, self.txs, self.number = block, [], 2**32 - 1
        self.totaldiff, self.invalid, self.mainchain = 0, False, False
        self.chained, self.succ = False, nullhash
Example #4
0
class AddressTimestamp(js.Entity, bs.Entity):
    fields = {
        "timestamp": js.Int,
        "services": js.Int,
        "ip": js.IPv4,
        "port": js.Int
    }
    bfields = [
        ("timestamp", bs.structfmt("<I")),
        ("services", bs.structfmt("<Q")),
        ("ip", bs.IPv4Inv6),
        ("port", bs.structfmt("!H")),
    ]

    def __eq__(self, other):
        if isinstance(other, Address):
            return self.ip == other.ip and self.port == other.port
        return False

    def __hash__(self):
        return hash(self.ip) ^ hash(self.port)

    @constructor
    def make(self, ip, port):
        self.services = 1  # Always 1 in current protocol
        self.ip = ip
        self.port = port
Example #5
0
class Address(js.Entity, bs.Entity):
    fields = {"services": js.Int, "ip": js.IPv4, "port": js.Int}
    bfields = [
        ("services", bs.structfmt("<Q")),
        ("ip", bs.IPv4Inv6),
        ("port", bs.structfmt("!H")),
    ]

    @constructor
    def make(self, ip, port):
        self.services = 1  # Always 1 in current protocol
        self.ip = ip
        self.port = port
Example #6
0
class merkelproof(js.Entity, bs.Entity):
    bfields = [
        ("pairs", bs.VarList(bs.structfmt("<32s32s"))),
        ("leaf", bs.Hash),
        ("block", bs.Hash),
    ]

    @constructor
    def make(self, block, tx):
        self.block = block.hash
        self.leaf = tx.hash
        self.pairs = utils.get_merkel_tree(block.txs, tx.hash)

    @cachedproperty
    def merkelroot(self):
        return doublesha("".join(self.pairs[-1]))

    @cachedproperty
    def valid(self, n):
        leaf = self.leaf
        for pair in pairs:
            if leaf not in pair:
                return False
            leaf = doublesha("".join(pair))
        return True
Example #7
0
class TxOutpoint(js.Entity, bs.Entity):
    fields = {
        "tx": js.Hash,
        "index": js.Int,
    }
    bfields = [
        ("tx", bs.Hash),
        ("index", bs.structfmt("<I")),
    ]
Example #8
0
class Tx(js.Entity, bs.Entity):
    type = "tx"
    fields = {
        "version": js.Int,
        "inputs": js.List(TxInput),
        "outputs": js.List(TxOutput),
        "locktime": js.Int,
    }
    bfields = [
        ("version", bs.structfmt("<I")),
        ("inputs", bs.VarList(TxInput)),
        ("outputs", bs.VarList(TxOutput)),
        ("locktime", bs.structfmt("<I")),
    ]

    @cachedproperty
    def hash(self):
        return doublesha(self.tobinary())
Example #9
0
class TxOutput(js.Entity, bs.Entity):
    fields = {
        "amount": js.Int,
        "script": js.Bytes,
    }
    bfields = [
        ("amount", bs.structfmt("<Q")),
        ("script", bs.VarBytes),
    ]
Example #10
0
class TimedAddress(js.Entity, bs.Entity):
    fields = {
        "lastseen": js.Int,
        "address": Address,
    }
    bfields = [
        ("lastseen", bs.structfmt("<I")),
        ("address", Address),
    ]
Example #11
0
class TxInput(js.Entity, bs.Entity):
    fields = {
        "outpoint": TxOutpoint,
        "script": js.Bytes,
        "sequence": js.Int,
    }
    bfields = [
        ("outpoint", TxOutpoint),
        ("script", bs.VarBytes),
        ("sequence", bs.structfmt("<I")),
    ]
Example #12
0
class Block(js.Entity, bs.Entity):
    fields = {
        "version": js.Int,
        "prev": js.Hash,
        "merkle": js.Hash,
        "time": js.Int,
        "bits": js.Int,
        "nonce": js.Int,
    }
    bfields = [
        ("version", bs.structfmt("<I")),
        ("prev", bs.Hash),
        ("merkle", bs.Hash),
        ("time", bs.structfmt("<I")),
        ("bits", bs.structfmt("<I")),
        ("nonce", bs.structfmt("<I")),
    ]

    @cachedproperty
    def hash(self):
        return doublesha(self.tobinary())
Example #13
0
class TxOutput(js.Entity, bs.Entity):
    fields = {
        "amount": js.Int,
        "script": js.Bytes,
    }
    bfields = [
        ("amount", bs.structfmt("<Q")),
        ("script", bs.VarBytes),
    ]

    def __repr__(self):
        return "<TxOut amount: %d>" % (self.amount)
Example #14
0
class Version(js.Entity, bs.Entity):
    type = "version"
    fields = {
        "type": js.Str,
        "version": js.Int,
        "services": js.Int,
        "time": js.Int,
        "reciever": Address,
        "sender": Address,
        "nonce": js.Int,
        "useragent": js.Str,
        "finalblock": js.Int,
        #"realy":js.Bool
    }
    bfields = [
        ("version", bs.structfmt("<I")),
        ("services", bs.structfmt("<Q")),
        ("time", bs.structfmt("<Q")),
        ("reciever", Address),
        ("sender", Address),
        ("nonce", bs.structfmt("<Q")),
        ("useragent", bs.VarBytes),
        ("finalblock", bs.structfmt("<I")),
        #("relay", bs.structfmt("<?"))
    ]

    @constructor
    def make(self,
             version=60000,
             sender=Address.make("0.0.0.0", 0),
             reciever=Address.make("0.0.0.0", 0),
             useragent="/pycoin:0.0.1/"):
        self.version = version
        self.services = 0
        self.time = int(time.time())
        self.sender = sender
        self.reciever = reciever
        self.nonce = 1234134124
        self.useragent = useragent
        self.finalblock = 1
Example #15
0
class TxPoint(js.Entity, bs.Entity):
    fields = {
        "tx": js.Hash,
        "index": js.Int,
    }
    bfields = [
        ("tx", bs.Hash),
        ("index", bs.structfmt("<I")),
    ]

    @constructor
    def make(self, tx, index):
        self.tx = tx
        self.index = index
Example #16
0
class Tx(js.Entity, bs.Entity):
    fields = {
        "tx": msgs.Tx,
        "block": js.Hash,
        "blkindex": js.Int,
        #"flags":js.Int,
        "redeemed": js.List(js.Hash),
    }
    bfields = [
        ("tx", msgs.Tx),
        ("block", bs.Hash),
        ("blkindex", bs.structfmt("<L")),
        #("flags", bs.VarInt),
        ("redeemed", bs.VarList(bs.Hash)),
    ]
Example #17
0
class TxInput(js.Entity, bs.Entity):
    fields = {
        "outpoint": TxPoint,
        "script": js.Bytes,
        "sequence": js.Int,
    }
    bfields = [
        ("outpoint", TxPoint),
        ("script", bs.VarBytes),
        ("sequence", bs.structfmt("<I")),
    ]

    def __repr__(self):
        return "<TxIn outpoint: %s:%d>" % (h2h(
            self.outpoint.tx), self.outpoint.index)
Example #18
0
class Getblocks(js.Entity, bs.Entity):
    type = "getblocks"
    fields = {
        "type": js.Str,
        "version": js.Int,
        "starts": js.List(js.Hash),
        "end": js.Hash,
    }
    bfields = [
        ("version", bs.structfmt("<I")),
        ("starts", bs.VarList(bs.Hash)),
        ("end", bs.Hash),
    ]

    @constructor
    def make(self, starts, end=b"\x00" * 32):
        self.version = 31900
        self.starts = starts
        self.end = end
Example #19
0
class InvVect(js.Entity, bs.Entity):
    fields = {
        "objtype": js.Int,
        "hash": js.Hash,
    }
    bfields = [
        ("objtype", bs.structfmt("<I")),
        ("hash", bs.Hash),
    ]

    def __eq__(self, other):
        if self.__class__ == other.__class__:
            return self.hash == other.hash and self.objtype == other.objtype
        return NotImplemented

    def __hash__(self):
        return hash(self.hash)

    @constructor
    def make(self, objtype, hash):
        self.objtype, self.hash = objtype, hash
Example #20
0
class Tx(js.Entity, bs.Entity):
    fields = {
        "tx": msgs.Tx,
        "block": js.Hash,
        "blkindex": js.Int,
        #"flags":js.Int,
        "redeemed": js.List(js.Hash),
    }
    bfields = [
        ("tx", msgs.Tx),
        ("block", bs.Hash),
        ("blkindex", bs.structfmt("<L")),
        #("flags", bs.VarInt),
        ("redeemed", bs.VarList(bs.Hash)),
    ]

    @staticmethod
    def get_by_hash(h):
        """get a transaction from the database.
        throws KeyError, if not found.
        """
        log.debug("getting tx %s", h2h(h))
        return Tx.frombinary(txs.get(h))[0]

    @txn_required
    def put(self):
        """update the database record of the transaction."""
        log.debug("putting tx %s", h2h(self.hash))
        if not Tx.exist(self.hash):
            for cb in settings.NEW_TX_HOOKS:
                cb(self)
        txs.put(self.hash, self.tobinary())

    @staticmethod
    def iter_tx():
        """loop though all transactions known to the database."""
        try:
            cur = txs.cursor()
            while True:
                try:
                    h, data = cur.next()
                except KeyError:
                    break
                yield Tx.frombinary(data)[0]
        finally:
            cur.close()

    @staticmethod
    @txn_required
    def get_or_make(txmsg):
        """get the database transaction, or make it from txmsg if it does not exist."""
        if not Tx.exist(txmsg.hash):
            tx = Tx.make(txmsg)
            tx.put()
        else:
            tx = Tx.get_by_hash(txmsg.hash)
        return tx

    @staticmethod
    def exist(h):
        """check if a transactions exist in the database"""
        return txs.has_key(h)

    @property
    def hash(self):
        return self.tx.hash

    @property
    def hexhash(self):
        return h2h(self.hash)

    @property
    def confirmed(self):
        return self.block != nullhash

    @property
    def inputs(self):
        return self.tx.inputs

    @property
    def outputs(self):
        return self.tx.outputs

    @property
    def coinbase(self):
        return self.tx.coinbase

    def get_block(self):
        """get the block in which this transaction is included. returns None, if the transaction is not confirmed"""
        if self.confirmed:
            return blockchain.Block.get_by_hash(self.block)
        else:
            return None

    def get_confirmations(self):
        """get the number of confirmations this transactions haves."""
        blk0 = self.get_block()
        if not blk0:
            return 0
        blk1 = blockchain.get_bestblock()
        return blk1.number - blk0.number + 1

    @txn_required
    def confirm(self, block, blkidx=0, coinbase=False):
        log.info("confirming tx %s", h2h(self.hash))
        self.block = block.hash
        self.blkindex = blkidx
        if settings.TX_CHECK_SCRIPTS:
            self.check_signatures()
        if coinbase:
            return
        for inp in self.tx.inputs:
            inp_tx = Tx.get_by_hash(inp.outpoint.tx)
            inp_tx.redeem_output(inp.outpoint, self)
            inp_tx.put()

    def revert(self, block=None, coinbase=False):
        log.info("reverting tx %s", h2h(self.hash))
        self.block = nullhash
        if coinbase:
            return
        for inp in self.tx.inputs:
            inp_tx = Tx.get_by_hash(inp.outpoint.tx)
            inp_tx.unredeem_output(inp.outpoint)
            inp_tx.put()

    def get_amount_out(self):
        return sum(i.amount for i in self.tx.outputs)

    def get_amount_in(self, block=None, coinbase=False):
        if self.coinbase:
            if coinbase and block:
                reward = 50 * COIN >> (block.number / 210000)
                fees = block.get_all_fees()
                return reward + fees
            else:
                return 0
        amount = 0
        for inp in self.tx.inputs:
            amount += Tx.get_outpoint(inp.outpoint).amount
        return amount

    def get_fee(self):
        if self.coinbase:
            return 0
        return self.get_amount_in() - self.get_amount_out()

    def verify(self,
               check_spend=False,
               check_scripts=False,
               block=None,
               coinbase=False):
        if self.total_amount_out() > self.total_amount_in(block=block):
            return False
        if check_spend:
            pass  #TODO: check if all inputs are not spend yet
        if check_scripts:
            return self.check_signatures()
        return True

    def __repr__(self):
        return "<Tx %s, %d inputs, %d outputs, coinbase: %s, in: %d, out: %d, fees: %d>" % (
            h2h(self.hash), len(self.tx.inputs), len(
                self.tx.outputs), str(self.coinbase), self.get_amount_in(),
            self.get_amount_out(), self.get_fee())

    def get_simple_hash(self, inputidx, hashtype):
        assert hashtype == 1
        tx = msgs.Tx.frombinary(self.tx.tobinary())[0]  # copy the transaction
        for i, inp in enumerate(tx.inputs):
            if i == inputidx:
                outp = Tx.get_outpoint(inp.outpoint)
                inp.script = outp.script
            else:
                inp.script = ""
        return doublesha(tx.tobinary() + struct.pack("<L", hashtype))

    def extract_info(self, inputidx):
        inp = self.inputs[inputidx]
        outp = Tx.get_outpoint(inp.outpoint)
        if outp.script[:2] == "\x76\xa9" and outp.script[
                -2:] == "\x88\xac":  #to address
            address = outp.script[3:-2]
            rest = inp.script
            sig_l, rest = ord(rest[0]), rest[1:]
            sig, rest = rest[:sig_l], rest[sig_l:]
            key_l, rest = ord(rest[0]), rest[1:]
            key, rest = rest[:key_l], rest[key_l:]
            if rest != "" or len(key) != key_l or len(sig) != sig_l:
                return (0, None, None, None)
            return (1, address, sig, key)
        if outp.script[-1:] == "\xac":  # generation
            rest = outp.script
            key_l, rest = ord(rest[0]), rest[1:]
            key, rest = rest[:key_l], rest[key_l:]
            if rest != "\xac":
                return (0, None, None, None)
            rest = inp.script
            sig_l, rest = ord(rest[0]), rest[1:]
            sig, rest = rest[:sig_l], rest[sig_l:]
            if rest != "":
                return (0, None, None, None)
            if len(key) != key_l or len(sig) != sig_l:
                return (0, None, None, None)
            return (2, None, sig, key)

    def check_signatures(self):
        if self.coinbase:
            return True
        for idx in range(len(self.inputs)):
            sc_type, address, sig, keystr = self.extract_info(idx)

            if sc_type == 0:
                log.warning(
                    "tx input %s:%d could not be validated, could not extract info",
                    h2h(self.hash), idx)
                continue
            if sc_type == 1:
                log.info("tx input %s:%d, is in address-form", h2h(self.hash),
                         idx)
                if hash160(key) != address:
                    log.warning(
                        "tx input %s:%d is invalid, address and publickey does not match",
                        h2h(self.hash), idx)
                    return False
            elif sc_type == 2:
                log.info("tx input %s:%d is from coin generation",
                         h2h(self.hash), idx)

            sig, hashtype = ec.load_sig(sig)
            if hashtype != 1:
                log.warning(
                    "tx input %s:%d could not be validated, hashtype is wrong",
                    h2h(self.hash), idx)
                continue

            simple_hash = self.get_simple_hash(idx, hashtype)
            key = ec.Key.from_pubkey(keystr)
            res = key.verify(simple_hash, sig)
            if res:
                log.info("tx input %s:%d, is valid", h2h(self.hash), idx)
            else:
                log.warning("tx input %s:%d, is invalid, signature is invalid",
                            h2h(self.hash), idx)
                return False
        return True

    @constructor
    def make(self, tx):
        self.tx, self.block = tx, nullhash
        self.blkindex = 0
        self.redeemed = [nullhash] * len(tx.outputs)

    def get_inpoint(self, i):
        return msgs.TxPoint(self.hash, i)

    @staticmethod
    def get_outpoint(outpoint, txn=None):
        tx = Tx.get_by_hash(outpoint.tx)
        assert outpoint.index < len(tx.outputs), "outpoint index out of range"
        return tx.outputs[outpoint.index]

    def is_redeemed(self, outpoint):
        assert self.hash == outpoint.tx, "outpoint hash does not point to tx"
        assert outpoint.index < len(
            self.tx.outputs), "outpoint index out of range"
        return self.redeemed[outpoint.index] != nullhash

    def redeem_output(self, outpoint, tx):
        assert self.hash == outpoint.tx, "outpoint hash does not point to tx"
        assert outpoint.index < len(
            self.tx.outputs), "outpoint index out of range"
        if self.redeemed[outpoint.index] != nullhash:
            raise TxInputAlreadySpend(outpoint)
        self.redeemed[outpoint.index] = tx.hash

    def unredeem_output(self, outpoint):
        assert self.hash == outpoint.tx, "outpoint hash does not point to tx"
        assert outpoint.index < len(
            self.tx.outputs), "outpoint index out of range"
        self.redeemed[outpoint.index] = nullhash

    def fully_redeemed(self):
        return nullhash not in self.redeemed
Example #21
0
class Block(js.Entity, bs.Entity):
    fields = {
        "block": msgs.Block,
        "number": js.Int,
        "totaldiff": js.Int,
        "chain": js.Int,
        "txs": js.List(js.Hash),
        "nexts": js.List(js.Hash)
    }
    bfields = [("block", msgs.Block), ("number", bs.structfmt("<L")),
               ("totaldiff", bs.structfmt("<Q")),
               ("chain", bs.structfmt("<B")), ("txs", bs.VarList(bs.Hash)),
               ("nexts", bs.VarList(bs.Hash))]

    @property
    def hash(self):
        return self.block.hash

    @property
    def hexhash(self):
        return h2h(self.hash)

    @property
    def prev(self):
        return self.block.prev

    @staticmethod
    def iter_blocks():
        i = 0
        while True:
            try:
                yield Block.get_by_number(i)
            except KeyError:
                raise StopIteration
            i += 1

    @staticmethod
    def get_by_hash(h):
        log.debug("getting block %s", h2h(h))
        return Block.frombinary(chain.get(h))[0]

    @staticmethod
    def get_by_number(num):
        h = blknums.get(str(num))
        return Block.get_by_hash(h)

    @staticmethod
    def exist_by_hash(h):
        return chain.has_key(h)

    @staticmethod
    def exist_by_number(num):
        return blknums.has_key(str(num))

    @staticmethod
    def get_or_make(blkmsg):
        if not Block.exist_by_hash(blkmsg.hash):
            blk = Block.make(blkmsg)
            for txmsg in blkmsg.txs:
                tx = transactions.Tx.get_or_make(txmsg)
                if tx: tx.put()
            blk.link()
            blk.put()
        else:
            blk = Block.get_by_hash(blkmsg.hash)
        return blk

    @txn_required
    def put(self):
        if self.chain == ORPHAN_CHAIN:
            log.debug("trying to put orphan block in db? (bug?)")
            return False
        log.debug("putting block %s", h2h(self.hash))
        chain.put(self.hash, self.tobinary())
        if self.chain == MAIN_CHAIN:
            blknums.put(str(self.number), self.hash)

    def get_tx(self, idx):
        return transactions.Tx.get_by_hash(self.txs[idx])

    def iter_tx(self, from_idx=0, to_idx=None, reverse=False, enum=False):
        sl = list(enumerate(self.txs[from_idx:to_idx], start=from_idx))
        if reverse: sl.reverse()
        if enum:
            for blkidx, tx_h in sl:
                yield (blkidx, transactions.Tx.get_by_hash(tx_h))
        else:
            for blkidx, tx_h in sl:
                yield transactions.Tx.get_by_hash(tx_h)

    def get_prev(self):
        return Block.get_by_hash(self.prev)

    def get_next_bits(self):
        targettimespan = 14 * 24 * 60 * 60  # 2 weeks in secounds
        spacing = 10 * 60  # 10 min in secounds
        interval = targettimespan / spacing  # 2 weeks of blocks(2016)
        if (self.number + 1) % interval != 0:
            return self.block.bits
        log.info("DIFF: retarget, current bits: %s", hex(self.block.bits))
        first_blk = self
        for i in range(interval - 1):
            first_blk = first_blk.get_prev()
        realtimespan = self.block.time - first_blk.block.time
        log.info("DIFF: timespan before limits: %d", realtimespan)
        if realtimespan < targettimespan / 4: realtimespan = targettimespan / 4
        if realtimespan > targettimespan * 4: realtimespan = targettimespan * 4
        log.info("DIFF: timespan after limits: %d", realtimespan)
        newtarget = (bits_to_target(self.block.bits) *
                     realtimespan) / targettimespan
        if newtarget > bits_to_target(0x1d00ffff):
            newtarget = bits_to_target(0x1d00ffff)
        bits = target_to_bits(newtarget)
        log.info("DIFF: next bits: %s", hex(bits))
        return bits

    def verify(self):
        if self.chain == INVALID_CHAIN:
            return False
        if not check_bits(self.block.bits, self.hash):
            return False
        prev_blk = self.get_prev()
        if prev_blk.chain == INVALID_CHAIN:
            return False
        if prev_blk.get_next_bits() != self.block.bits:
            return False
        return True

    @txn_required
    def confirm(self):
        log.info("confirming block %s(%d)", h2h(self.hash), self.number)
        if not self.verify():
            raise Invalidblock()
        if not set_bestblock(self):
            log.info("block %s(%d) not good", h2h(self.hash), self.number)
            return False
        self.chain = MAIN_CHAIN
        self.put()
        run_hooks(settings.BLOCK_CONFIRM_HOOKS, self)

    @txn_required
    def revert(self):
        log.info("reverting block %s(%d)", h2h(self.hash), self.number)
        set_bestblock(self.get_prev(), check=False)
        if self.chain != MAIN_CHAIN:
            log.debug("reverting a block, that is not in main chain? (bug?)")
        self.chain = SIDE_CHAIN
        self.put()
        run_hooks(settings.BLOCK_REVERT_HOOKS, self)

    @txn_required
    def invalidate(self):
        self.chain = CHAIN_INVALID
        self.put()
        blocks_to_invalidate = set(self.nexts)
        while blocks_to_invalidate:
            blk_h = blocks_to_invalidate.pop()
            blk = Block.get_by_hash(blk_h)
            blk.chain = CHAIN_INVALID
            blk.put()
            blocks_to_invalidate.update(blk.nexts)

    @txn_required
    def link(self):
        prev = self.get_prev()
        prev.nexts.append(self.hash)
        prev.put()
        if prev.chain == MAIN_CHAIN:
            self.chain = SIDE_CHAIN
        else:
            self.chain = prev.chain
        if not self.verify():
            self.invalidate()
        self.number = prev.number + 1
        self.totaldiff = prev.totaldiff + bits_to_diff(self.block.bits)
        self.put()

    def get_all_fees(self):
        return sum(tx.get_fee() for tx in self.iter_tx())

    def changes_since(self):
        bestblock = get_bestblock()
        split, reverted, confirmed = find_split(self, bestblock)
        result = {}
        result["reverted"] = [(blk.hash, [tx_h for tx_h in blk.txs])
                              for blk in reverted]
        result["confirmed"] = [(blk.hash, [tx_h for tx_h in blk.txs])
                               for blk in confirmed]
        return result

    def __repr__(self):
        return "<Block %s(%d) - diff: %d - chain: %s, txs: %s>" % (
            self.hexhash, self.number, bits_to_diff(self.block.bits),
            _chains.get(self.chain, "unknown(BUG)"), len(self.txs))

    @constructor
    def make(self, blockmsg):
        self.block, self.txs = blockmsg.block, [tx.hash for tx in blockmsg.txs]
        self.number, self.totaldiff, self.chain, self.nexts = 0, 0, ORPHAN_CHAIN, []

    def tonetwork(self):
        return msgs.Blockmsg(self.block, list(self.iter_tx()))