Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rustyrussell/pettycoin
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 5a4c143c7946
Choose a base ref
...
head repository: rustyrussell/pettycoin
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 611822f9b131
Choose a head ref
  • 6 commits
  • 10 files changed
  • 1 contributor

Commits on Aug 8, 2014

  1. protocol: make testnet horizon 3 days.

    12 hours makes it horribly difficult to send test transfers across timezones;
    at least this gives us the weekend!
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    rustyrussell committed Aug 8, 2014
    Copy the full SHA
    806abc3 View commit details
  2. recv_children: handle case where block isn't known properly.

    We were falling through as if they said there were no children.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    rustyrussell committed Aug 8, 2014
    Copy the full SHA
    fad6220 View commit details
  3. peer: initiate new block query during sync.

    We currently get a surprise next time a new block is generated, and fall
    back to chasing prevs.  We should fix the sync protocol, but meanwhile, this
    means we at least get those blocks before we consider ourselves "synced"
    
    Note that this breaks our sync test: we don't get told about new blocks while
    we're syncing (and we do that for much longer now).  We would normally
    catch up when the next block arrived.  But we don't need the block inject
    at all anymore to force synchronization, so remove it.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    rustyrussell committed Aug 8, 2014
    Copy the full SHA
    a084648 View commit details
  4. blockfile: handle case where there are incomplete blocks in file.

    We want to ask about any transactions we don't know about once we've loaded
    the blocks and transactions off disk.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    rustyrussell committed Aug 8, 2014

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    28098f4 View commit details

Commits on Aug 9, 2014

  1. peer: use recv_tx_from_peer().

    We made the code more general and moved it into recv_tx.c, but never called
    it!  Fix that so we don't have duplicated code (they're currently identical).
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    rustyrussell committed Aug 9, 2014
    Copy the full SHA
    ba0fe87 View commit details
  2. check_block: don't hit think the current tx is a dup in check_tx_inpu…

    …ts_and_refs
    
    We weren't excluding the existing transaction, which can happen when we're
    doing check_resolved_txs().  This makes us think there's a doublespend
    in the block!
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    rustyrussell committed Aug 9, 2014
    Copy the full SHA
    611822f View commit details
Showing with 54 additions and 131 deletions.
  1. +21 −0 blockfile.c
  2. +5 −3 check_block.c
  3. +2 −1 check_block.h
  4. +7 −119 peer.c
  5. +2 −2 protocol.h
  6. +2 −2 recv_block.c
  7. +3 −0 recv_block.h
  8. +8 −2 recv_tx.c
  9. +1 −0 sync.c
  10. +3 −2 test/blackbox/test-01-sync.sh
21 changes: 21 additions & 0 deletions blockfile.c
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
#include "packet_io.h"
#include "proof.h"
#include "protocol_net.h"
#include "recv_block.h"
#include "recv_tx.h"
#include "shard.h"
#include "state.h"
@@ -99,6 +100,23 @@ static struct io_plan *setup_load_conn(struct io_conn *conn,
return io_read_packet(conn, &ls->pkt, load_packet, ls);
}

/* This can happen if we didn't know some TXs when we exited. */
static void get_unknown_contents(struct state *state)
{
unsigned int i;
const struct block *b;

for (i = 0; i < tal_count(state->longest_chains); i++) {
for (b = state->longest_chains[i]; b; b = b->prev) {
/* Stop if we know from here down. */
if (b->all_known)
break;

get_block_contents(state, b);
}
}
}

void load_blocks(struct state *state)
{
int fd;
@@ -138,6 +156,9 @@ void load_blocks(struct state *state)
log_info(state->log, "Checking chains...");
check_chains(state, true);
log_add(state->log, " ...completed");

/* If there are any txs we want to know and don't, ask. */
get_unknown_contents(state);
}

void save_block(struct state *state, struct block *new)
8 changes: 5 additions & 3 deletions check_block.c
Original file line number Diff line number Diff line change
@@ -164,7 +164,8 @@ static bool recheck_tx(struct state *state,
te->txoff),
block_get_refs(te->u.block,
te->shardnum,
te->txoff))) {
te->txoff),
te)) {
/* Caller will retry... */
return false;
}
@@ -400,15 +401,16 @@ bool check_tx_inputs_and_refs(struct state *state,
struct block *b,
const struct protocol_proof *proof,
union protocol_tx *tx,
struct protocol_input_ref *refs)
struct protocol_input_ref *refs,
const struct txhash_elem *me)
{
enum input_ecode ierr;
enum ref_ecode rerr;
unsigned int bad_input_num;
struct block *block_referred_to;

/* Check bad inputs, and generate complaints. */
ierr = check_tx_inputs(state, b, NULL, tx, &bad_input_num);
ierr = check_tx_inputs(state, b, me, tx, &bad_input_num);
switch (ierr) {
case ECODE_INPUT_OK:
break;
3 changes: 2 additions & 1 deletion check_block.h
Original file line number Diff line number Diff line change
@@ -71,7 +71,8 @@ bool check_tx_inputs_and_refs(struct state *state,
struct block *block,
const struct protocol_proof *proof,
union protocol_tx *tx,
struct protocol_input_ref *refs);
struct protocol_input_ref *refs,
const struct txhash_elem *me);

/* Various assertions about a block */
void check_block(struct state *state, const struct block *block, bool all);
126 changes: 7 additions & 119 deletions peer.c
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
#include "protocol_net.h"
#include "recv_block.h"
#include "recv_complain.h"
#include "recv_tx.h"
#include "shadouble.h"
#include "shard.h"
#include "state.h"
@@ -963,124 +964,6 @@ recv_get_tx(struct peer *peer,
return PROTOCOL_ECODE_NONE;
}

static enum protocol_ecode
recv_tx_in_block(struct peer *peer, const struct protocol_pkt_tx_in_block *pkt)
{
enum protocol_ecode e;
union protocol_tx *tx;
struct protocol_input_ref *refs;
struct protocol_tx_with_proof *proof;
struct block *b;
struct protocol_double_sha sha;
u16 shard;
u8 conflict_txoff;
size_t len = le32_to_cpu(pkt->len), used;

if (len < sizeof(*pkt))
return PROTOCOL_ECODE_INVALID_LEN;

len -= sizeof(*pkt);

e = le32_to_cpu(pkt->err);
if (e) {
struct protocol_position *pos = (void *)(pkt + 1);

if (len != sizeof(*pos))
return PROTOCOL_ECODE_INVALID_LEN;

if (e == PROTOCOL_ECODE_UNKNOWN_BLOCK) {
/* They don't know block at all, so don't ask. */
todo_done_get_block(peer, &pos->block, false);
} else if (e != PROTOCOL_ECODE_UNKNOWN_TX)
return PROTOCOL_ECODE_UNKNOWN_ERRCODE;

todo_done_get_tx_in_block(peer, &pos->block,
le16_to_cpu(pos->shard),
pos->txoff, false);
return PROTOCOL_ECODE_NONE;
}

if (len < sizeof(*proof))
return PROTOCOL_ECODE_INVALID_LEN;
len -= sizeof(*proof);

proof = (void *)(pkt + 1);
shard = le16_to_cpu(proof->proof.pos.shard);

b = block_find_any(peer->state, &proof->proof.pos.block);
if (!b) {
todo_add_get_block(peer->state, &proof->proof.pos.block);
/* FIXME: should we extract transaction? */
return PROTOCOL_ECODE_NONE;
}

/* FIXME: We could check the proof before we check the tx & refs,
* then if a buggy implementation tried to send us invalid tx
* and refs we could turn it into a complaint. */

tx = (void *)(proof + 1);
e = unmarshal_tx(tx, len, &used);
if (e)
return e;
len -= used;

/* You can't send us bad txs this way: use a complaint packet. */
e = check_tx(peer->state, tx, b);
if (e)
return e;

refs = (void *)((char *)tx + used);
e = unmarshal_input_refs(refs, len, tx, &used);
if (e)
return e;

if (used != len)
return PROTOCOL_ECODE_INVALID_LEN;

e = check_refs(peer->state, b, refs, num_inputs(tx));
if (e)
return e;

if (!check_proof(&proof->proof, b, tx, refs))
return PROTOCOL_ECODE_BAD_PROOF;

/* Whatever happens from here, no point asking others for tx. */
todo_done_get_tx_in_block(peer, &proof->proof.pos.block,
shard, proof->proof.pos.txoff, true);

/* This may have been a response to GET_TX as well. */
hash_tx(tx, &sha);
todo_done_get_tx(peer, &sha, true);

/* Now it's proven that it's in the block, handle bad inputs/refs.
* We don't hang up on them, since they may not have known. */
if (!check_tx_inputs_and_refs(peer->state, b, &proof->proof, tx, refs))
return PROTOCOL_ECODE_NONE;

/* Simularly, they might not know if it was misordered. */
if (!check_tx_ordering(peer->state, b, b->shard[shard],
proof->proof.pos.txoff, tx, &conflict_txoff)) {
/* Tell everyone that txs are out of order in block */
complain_misorder(peer->state, b, &proof->proof,
tx, refs, conflict_txoff);
return PROTOCOL_ECODE_NONE;
}

/* Keep proof in case anyone asks. */
put_proof_in_shard(peer->state, b, &proof->proof);
/* Copy in tx and refs. */
put_tx_in_shard(peer->state, peer,
b, b->shard[shard], proof->proof.pos.txoff,
txptr_with_ref(b->shard[shard], tx, refs));

/* This is OK for now, will be spammy in real network! */
log_info(peer->log, "gave us TX in shard %u, off %u, block %u ",
shard, proof->proof.pos.txoff, le32_to_cpu(b->hdr->height));
log_add_struct(peer->log, struct protocol_double_sha, &sha);

return PROTOCOL_ECODE_NONE;
}

static enum protocol_ecode
recv_get_txmap(struct peer *peer, const struct protocol_pkt_get_txmap *pkt,
void **reply)
@@ -1473,7 +1356,7 @@ static struct io_plan *pkt_in(struct io_conn *conn, struct peer *peer)
err = recv_get_tx_in_block(peer, peer->incoming, &reply);
break;
case PROTOCOL_PKT_TX_IN_BLOCK:
err = recv_tx_in_block(peer, peer->incoming);
err = recv_tx_from_peer(peer, peer->incoming);
break;
case PROTOCOL_PKT_GET_TX:
err = recv_get_tx(peer, peer->incoming, &reply);
@@ -1640,6 +1523,11 @@ static struct io_plan *welcome_received(struct io_conn *conn, struct peer *peer)

mutual = mutual_block_search(peer, peer->welcome_blocks,
le16_to_cpu(peer->welcome->num_blocks));

/* If we didn't know their best packet, start querying now. */
if (!block_find_any(peer->state, &peer->welcome_blocks[0]))
todo_add_get_block(peer->state, &peer->welcome_blocks[0]);

return peer_write_packet(peer, sync_or_horizon_pkt(peer, mutual),
recv_sync_or_horizon);
}
4 changes: 2 additions & 2 deletions protocol.h
Original file line number Diff line number Diff line change
@@ -27,9 +27,9 @@
/* How long between blocks (seconds): 10 seconds on testnet, 10 mins on main */
#define PROTOCOL_BLOCK_TARGET_TIME(testnet) ((testnet) ? 10 : 600)

/* How long (seconds) until transactions are obsolete (30 days / 12 hours) */
/* How long (seconds) until transactions are obsolete (30 days / 3 days) */
#define PROTOCOL_TX_HORIZON_SECS(testnet) \
(PROTOCOL_BLOCK_TARGET_TIME(testnet) * 6 * 24 * 30)
((testnet) ? 60 * 60 * 24 * 3 : 60 * 60 * 24 * 30)

/* How many blocks form a difficulty set (1 fortnight, a-la bitcoin) */
#define PROTOCOL_DIFFICULTY_UPDATE_BLOCKS 2016
4 changes: 2 additions & 2 deletions recv_block.c
Original file line number Diff line number Diff line change
@@ -80,7 +80,7 @@ static void seek_predecessor(struct state *state,
}

/* When syncing, we ask for txmaps. */
static void sync_block_contents(struct state *state, const struct block *b)
void get_block_contents(struct state *state, const struct block *b)
{
unsigned int shard;

@@ -185,7 +185,7 @@ recv_block(struct state *state, struct log *log, struct peer *peer,
/* If we're syncing, ask about children, contents */
if (peer && peer->we_are_syncing) {
todo_add_get_children(state, &b->sha);
sync_block_contents(state, b);
get_block_contents(state, b);
} else {
/* Otherwise, tell peers about new block. */
send_block_to_peers(state, peer, b);
3 changes: 3 additions & 0 deletions recv_block.h
Original file line number Diff line number Diff line change
@@ -30,4 +30,7 @@ bool try_resolve_hash(struct state *state,
/* A new block: see if it resolved any prev_block */
void seek_detached_blocks(struct state *state,
const struct block *block);

/* Ask about block contents (on startup and syncing) */
void get_block_contents(struct state *state, const struct block *b);
#endif /* PETTYCOIN_RECV_BLOCK_H */
10 changes: 8 additions & 2 deletions recv_tx.c
Original file line number Diff line number Diff line change
@@ -58,7 +58,6 @@ recv_tx(struct state *state,
len -= sizeof(*proof);

proof = (void *)(pkt + 1);
shard = le16_to_cpu(proof->proof.pos.shard);

b = block_find_any(state, &proof->proof.pos.block);
if (!b) {
@@ -98,6 +97,9 @@ recv_tx(struct state *state,
if (!check_proof(&proof->proof, b, tx, refs))
return PROTOCOL_ECODE_BAD_PROOF;

/* Now we know shard (and txoff) is valid. */
shard = le16_to_cpu(proof->proof.pos.shard);

/* Whatever happens from here, no point asking others for tx. */
if (peer)
todo_done_get_tx_in_block(peer, &proof->proof.pos.block,
@@ -108,9 +110,13 @@ recv_tx(struct state *state,
if (peer)
todo_done_get_tx(peer, &sha, true);

/* If we already have it, we're done. */
if (block_get_tx(b, shard, proof->proof.pos.txoff))
return PROTOCOL_ECODE_NONE;

/* Now it's proven that it's in the block, handle bad inputs/refs.
* We don't hang up on them, since they may not have known. */
if (!check_tx_inputs_and_refs(state, b, &proof->proof, tx, refs))
if (!check_tx_inputs_and_refs(state, b, &proof->proof, tx, refs, NULL))
return PROTOCOL_ECODE_NONE;

/* Simularly, they might not know if it was misordered. */
1 change: 1 addition & 0 deletions sync.c
Original file line number Diff line number Diff line change
@@ -196,6 +196,7 @@ enum protocol_ecode recv_children(struct peer *peer,
return PROTOCOL_ECODE_UNKNOWN_COMMAND;
/* They don't know the block. OK. */
todo_done_get_children(peer, &pkt->block, false);
return PROTOCOL_ECODE_NONE;
}

len = le32_to_cpu(pkt->len) - sizeof(*pkt);
5 changes: 3 additions & 2 deletions test/blackbox/test-01-sync.sh
Original file line number Diff line number Diff line change
@@ -29,8 +29,9 @@ while [ $(date +%s) -lt $END ]; do
sleep 5
done

# Give P1 new block, will trigger P2 to ask.
$RUNPREFIX/pettycoin-query --pettycoin-dir=$SCRATCHDIR/p1 submitblock $NEWBLOCK
# FIXME: This doesn't go to P2, which is still syncing!
## Give P1 new block, will trigger P2 to ask.
#$RUNPREFIX/pettycoin-query --pettycoin-dir=$SCRATCHDIR/p1 submitblock $NEWBLOCK

while [ $(date +%s) -lt $END ]; do
DEPTH1=`$RUNPREFIX/pettycoin-query --pettycoin-dir=$SCRATCHDIR/p1 getinfo | sed -n 's/.*"height" : \([0-9]\+\) .*num_todos.*/\1/p'`