3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-12 10:15:52 +00:00

Some fixes to wallet serialization:

1) Switch the outpoint index field to be uint32 and fix isCoinBase() to consider the unsigned versions only. Resolves issue 420.
2) Regenerate the protobuf and fix an out of date definition in WalletProtobufSerializer that it exposed.
This commit is contained in:
Mike Hearn 2013-06-27 14:01:02 +02:00
parent 7f68923529
commit c4572696b1
5 changed files with 62 additions and 48 deletions

View File

@ -81,7 +81,7 @@ message TransactionInput {
// Hash of the transaction this input is using. // Hash of the transaction this input is using.
required bytes transaction_out_point_hash = 1; required bytes transaction_out_point_hash = 1;
// Index of transaction output used by this input. // Index of transaction output used by this input.
required int32 transaction_out_point_index = 2; required uint32 transaction_out_point_index = 2;
// Script that contains the signatures/pubkeys. // Script that contains the signatures/pubkeys.
required bytes script_bytes = 3; required bytes script_bytes = 3;
// Sequence number. Currently unused, but intended for contracts in future. // Sequence number. Currently unused, but intended for contracts in future.

View File

@ -150,7 +150,7 @@ public class TransactionInput extends ChildMessage implements Serializable {
public boolean isCoinBase() { public boolean isCoinBase() {
maybeParse(); maybeParse();
return outpoint.getHash().equals(Sha256Hash.ZERO_HASH) && return outpoint.getHash().equals(Sha256Hash.ZERO_HASH) &&
outpoint.getIndex() == NO_SEQUENCE; (outpoint.getIndex() & 0xFFFFFFFFL) == 0xFFFFFFFFL; // -1 but all is serialized to the wire as unsigned int.
} }
/** /**

View File

@ -440,7 +440,7 @@ public class WalletProtobufSerializer {
for (Protos.TransactionInput transactionInput : txProto.getTransactionInputList()) { for (Protos.TransactionInput transactionInput : txProto.getTransactionInputList()) {
byte[] scriptBytes = transactionInput.getScriptBytes().toByteArray(); byte[] scriptBytes = transactionInput.getScriptBytes().toByteArray();
TransactionOutPoint outpoint = new TransactionOutPoint(params, TransactionOutPoint outpoint = new TransactionOutPoint(params,
transactionInput.getTransactionOutPointIndex(), transactionInput.getTransactionOutPointIndex() & 0xFFFFFFFFL,
byteStringToHash(transactionInput.getTransactionOutPointHash()) byteStringToHash(transactionInput.getTransactionOutPointHash())
); );
TransactionInput input = new TransactionInput(params, tx, scriptBytes, outpoint); TransactionInput input = new TransactionInput(params, tx, scriptBytes, outpoint);
@ -515,7 +515,7 @@ public class WalletProtobufSerializer {
case DEAD: confidenceType = ConfidenceType.DEAD; break; case DEAD: confidenceType = ConfidenceType.DEAD; break;
// These two are equivalent (must be able to read old wallets). // These two are equivalent (must be able to read old wallets).
case NOT_IN_BEST_CHAIN: confidenceType = ConfidenceType.PENDING; break; case NOT_IN_BEST_CHAIN: confidenceType = ConfidenceType.PENDING; break;
case NOT_SEEN_IN_CHAIN: confidenceType = ConfidenceType.PENDING; break; case PENDING: confidenceType = ConfidenceType.PENDING; break;
case UNKNOWN: case UNKNOWN:
// Fall through. // Fall through.
default: default:

View File

@ -1761,7 +1761,7 @@ public final class Protos {
boolean hasTransactionOutPointHash(); boolean hasTransactionOutPointHash();
com.google.protobuf.ByteString getTransactionOutPointHash(); com.google.protobuf.ByteString getTransactionOutPointHash();
// required int32 transaction_out_point_index = 2; // required uint32 transaction_out_point_index = 2;
boolean hasTransactionOutPointIndex(); boolean hasTransactionOutPointIndex();
int getTransactionOutPointIndex(); int getTransactionOutPointIndex();
@ -1812,7 +1812,7 @@ public final class Protos {
return transactionOutPointHash_; return transactionOutPointHash_;
} }
// required int32 transaction_out_point_index = 2; // required uint32 transaction_out_point_index = 2;
public static final int TRANSACTION_OUT_POINT_INDEX_FIELD_NUMBER = 2; public static final int TRANSACTION_OUT_POINT_INDEX_FIELD_NUMBER = 2;
private int transactionOutPointIndex_; private int transactionOutPointIndex_;
public boolean hasTransactionOutPointIndex() { public boolean hasTransactionOutPointIndex() {
@ -1876,7 +1876,7 @@ public final class Protos {
output.writeBytes(1, transactionOutPointHash_); output.writeBytes(1, transactionOutPointHash_);
} }
if (((bitField0_ & 0x00000002) == 0x00000002)) { if (((bitField0_ & 0x00000002) == 0x00000002)) {
output.writeInt32(2, transactionOutPointIndex_); output.writeUInt32(2, transactionOutPointIndex_);
} }
if (((bitField0_ & 0x00000004) == 0x00000004)) { if (((bitField0_ & 0x00000004) == 0x00000004)) {
output.writeBytes(3, scriptBytes_); output.writeBytes(3, scriptBytes_);
@ -1899,7 +1899,7 @@ public final class Protos {
} }
if (((bitField0_ & 0x00000002) == 0x00000002)) { if (((bitField0_ & 0x00000002) == 0x00000002)) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeInt32Size(2, transactionOutPointIndex_); .computeUInt32Size(2, transactionOutPointIndex_);
} }
if (((bitField0_ & 0x00000004) == 0x00000004)) { if (((bitField0_ & 0x00000004) == 0x00000004)) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
@ -2173,7 +2173,7 @@ public final class Protos {
} }
case 16: { case 16: {
bitField0_ |= 0x00000002; bitField0_ |= 0x00000002;
transactionOutPointIndex_ = input.readInt32(); transactionOutPointIndex_ = input.readUInt32();
break; break;
} }
case 26: { case 26: {
@ -2216,7 +2216,7 @@ public final class Protos {
return this; return this;
} }
// required int32 transaction_out_point_index = 2; // required uint32 transaction_out_point_index = 2;
private int transactionOutPointIndex_ ; private int transactionOutPointIndex_ ;
public boolean hasTransactionOutPointIndex() { public boolean hasTransactionOutPointIndex() {
return ((bitField0_ & 0x00000002) == 0x00000002); return ((bitField0_ & 0x00000002) == 0x00000002);
@ -2893,14 +2893,14 @@ public final class Protos {
implements com.google.protobuf.ProtocolMessageEnum { implements com.google.protobuf.ProtocolMessageEnum {
UNKNOWN(0, 0), UNKNOWN(0, 0),
BUILDING(1, 1), BUILDING(1, 1),
NOT_SEEN_IN_CHAIN(2, 2), PENDING(2, 2),
NOT_IN_BEST_CHAIN(3, 3), NOT_IN_BEST_CHAIN(3, 3),
DEAD(4, 4), DEAD(4, 4),
; ;
public static final int UNKNOWN_VALUE = 0; public static final int UNKNOWN_VALUE = 0;
public static final int BUILDING_VALUE = 1; public static final int BUILDING_VALUE = 1;
public static final int NOT_SEEN_IN_CHAIN_VALUE = 2; public static final int PENDING_VALUE = 2;
public static final int NOT_IN_BEST_CHAIN_VALUE = 3; public static final int NOT_IN_BEST_CHAIN_VALUE = 3;
public static final int DEAD_VALUE = 4; public static final int DEAD_VALUE = 4;
@ -2911,7 +2911,7 @@ public final class Protos {
switch (value) { switch (value) {
case 0: return UNKNOWN; case 0: return UNKNOWN;
case 1: return BUILDING; case 1: return BUILDING;
case 2: return NOT_SEEN_IN_CHAIN; case 2: return PENDING;
case 3: return NOT_IN_BEST_CHAIN; case 3: return NOT_IN_BEST_CHAIN;
case 4: return DEAD; case 4: return DEAD;
default: return null; default: return null;
@ -2944,7 +2944,7 @@ public final class Protos {
} }
private static final Type[] VALUES = { private static final Type[] VALUES = {
UNKNOWN, BUILDING, NOT_SEEN_IN_CHAIN, NOT_IN_BEST_CHAIN, DEAD, UNKNOWN, BUILDING, PENDING, NOT_IN_BEST_CHAIN, DEAD,
}; };
public static Type valueOf( public static Type valueOf(
@ -8311,47 +8311,47 @@ public final class Protos {
".\n\004Type\022\014\n\010ORIGINAL\020\001\022\030\n\024ENCRYPTED_SCRYP", ".\n\004Type\022\014\n\010ORIGINAL\020\001\022\030\n\024ENCRYPTED_SCRYP",
"T_AES\020\002\"\203\001\n\020TransactionInput\022\"\n\032transact" + "T_AES\020\002\"\203\001\n\020TransactionInput\022\"\n\032transact" +
"ion_out_point_hash\030\001 \002(\014\022#\n\033transaction_" + "ion_out_point_hash\030\001 \002(\014\022#\n\033transaction_" +
"out_point_index\030\002 \002(\005\022\024\n\014script_bytes\030\003 " + "out_point_index\030\002 \002(\r\022\024\n\014script_bytes\030\003 " +
"\002(\014\022\020\n\010sequence\030\004 \001(\r\"\177\n\021TransactionOutp" + "\002(\014\022\020\n\010sequence\030\004 \001(\r\"\177\n\021TransactionOutp" +
"ut\022\r\n\005value\030\001 \002(\003\022\024\n\014script_bytes\030\002 \002(\014\022" + "ut\022\r\n\005value\030\001 \002(\003\022\024\n\014script_bytes\030\002 \002(\014\022" +
"!\n\031spent_by_transaction_hash\030\003 \001(\014\022\"\n\032sp" + "!\n\031spent_by_transaction_hash\030\003 \001(\014\022\"\n\032sp" +
"ent_by_transaction_index\030\004 \001(\005\"\246\003\n\025Trans" + "ent_by_transaction_index\030\004 \001(\005\"\234\003\n\025Trans" +
"actionConfidence\0220\n\004type\030\001 \001(\0162\".wallet." + "actionConfidence\0220\n\004type\030\001 \001(\0162\".wallet." +
"TransactionConfidence.Type\022\032\n\022appeared_a" + "TransactionConfidence.Type\022\032\n\022appeared_a" +
"t_height\030\002 \001(\005\022\036\n\026overriding_transaction", "t_height\030\002 \001(\005\022\036\n\026overriding_transaction",
"\030\003 \001(\014\022\r\n\005depth\030\004 \001(\005\022\021\n\twork_done\030\005 \001(\003" + "\030\003 \001(\014\022\r\n\005depth\030\004 \001(\005\022\021\n\twork_done\030\005 \001(\003" +
"\022)\n\014broadcast_by\030\006 \003(\0132\023.wallet.PeerAddr" + "\022)\n\014broadcast_by\030\006 \003(\0132\023.wallet.PeerAddr" +
"ess\0224\n\006source\030\007 \001(\0162$.wallet.Transaction" + "ess\0224\n\006source\030\007 \001(\0162$.wallet.Transaction" +
"Confidence.Source\"Y\n\004Type\022\013\n\007UNKNOWN\020\000\022\014" + "Confidence.Source\"O\n\004Type\022\013\n\007UNKNOWN\020\000\022\014" +
"\n\010BUILDING\020\001\022\025\n\021NOT_SEEN_IN_CHAIN\020\002\022\025\n\021N" + "\n\010BUILDING\020\001\022\013\n\007PENDING\020\002\022\025\n\021NOT_IN_BEST" +
"OT_IN_BEST_CHAIN\020\003\022\010\n\004DEAD\020\004\"A\n\006Source\022\022" + "_CHAIN\020\003\022\010\n\004DEAD\020\004\"A\n\006Source\022\022\n\016SOURCE_U" +
"\n\016SOURCE_UNKNOWN\020\000\022\022\n\016SOURCE_NETWORK\020\001\022\017" + "NKNOWN\020\000\022\022\n\016SOURCE_NETWORK\020\001\022\017\n\013SOURCE_S" +
"\n\013SOURCE_SELF\020\002\"\211\003\n\013Transaction\022\017\n\007versi" + "ELF\020\002\"\211\003\n\013Transaction\022\017\n\007version\030\001 \002(\005\022\014" +
"on\030\001 \002(\005\022\014\n\004hash\030\002 \002(\014\022&\n\004pool\030\003 \001(\0162\030.w" + "\n\004hash\030\002 \002(\014\022&\n\004pool\030\003 \001(\0162\030.wallet.Tran" +
"allet.Transaction.Pool\022\021\n\tlock_time\030\004 \001(", "saction.Pool\022\021\n\tlock_time\030\004 \001(\r\022\022\n\nupdat",
"\r\022\022\n\nupdated_at\030\005 \001(\003\0223\n\021transaction_inp" + "ed_at\030\005 \001(\003\0223\n\021transaction_input\030\006 \003(\0132\030" +
"ut\030\006 \003(\0132\030.wallet.TransactionInput\0225\n\022tr" + ".wallet.TransactionInput\0225\n\022transaction_" +
"ansaction_output\030\007 \003(\0132\031.wallet.Transact" + "output\030\007 \003(\0132\031.wallet.TransactionOutput\022" +
"ionOutput\022\022\n\nblock_hash\030\010 \003(\014\0221\n\nconfide" + "\022\n\nblock_hash\030\010 \003(\014\0221\n\nconfidence\030\t \001(\0132" +
"nce\030\t \001(\0132\035.wallet.TransactionConfidence" + "\035.wallet.TransactionConfidence\"Y\n\004Pool\022\013" +
"\"Y\n\004Pool\022\013\n\007UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INAC" + "\n\007UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002\022\010\n\004" +
"TIVE\020\002\022\010\n\004DEAD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING" + "DEAD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_INACTIVE\020" +
"_INACTIVE\020\022\"N\n\020ScryptParameters\022\014\n\004salt\030" + "\022\"N\n\020ScryptParameters\022\014\n\004salt\030\001 \002(\014\022\020\n\001n" +
"\001 \002(\014\022\020\n\001n\030\002 \001(\003:\00516384\022\014\n\001r\030\003 \001(\005:\0018\022\014\n" + "\030\002 \001(\003:\00516384\022\014\n\001r\030\003 \001(\005:\0018\022\014\n\001p\030\004 \001(\005:\001" +
"\001p\030\004 \001(\005:\0011\"8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004", "1\"8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004data\030\002 \002(\014",
"data\030\002 \002(\014\022\021\n\tmandatory\030\003 \002(\010\"\255\003\n\006Wallet" + "\022\021\n\tmandatory\030\003 \002(\010\"\255\003\n\006Wallet\022\032\n\022networ" +
"\022\032\n\022network_identifier\030\001 \002(\t\022\034\n\024last_see" + "k_identifier\030\001 \002(\t\022\034\n\024last_seen_block_ha" +
"n_block_hash\030\002 \001(\014\022\036\n\026last_seen_block_he" + "sh\030\002 \001(\014\022\036\n\026last_seen_block_height\030\014 \001(\r" +
"ight\030\014 \001(\r\022\030\n\003key\030\003 \003(\0132\013.wallet.Key\022(\n\013" + "\022\030\n\003key\030\003 \003(\0132\013.wallet.Key\022(\n\013transactio" +
"transaction\030\004 \003(\0132\023.wallet.Transaction\022C" + "n\030\004 \003(\0132\023.wallet.Transaction\022C\n\017encrypti" +
"\n\017encryption_type\030\005 \001(\0162\035.wallet.Wallet." + "on_type\030\005 \001(\0162\035.wallet.Wallet.Encryption" +
"EncryptionType:\013UNENCRYPTED\0227\n\025encryptio" + "Type:\013UNENCRYPTED\0227\n\025encryption_paramete" +
"n_parameters\030\006 \001(\0132\030.wallet.ScryptParame" + "rs\030\006 \001(\0132\030.wallet.ScryptParameters\022\017\n\007ve" +
"ters\022\017\n\007version\030\007 \001(\005\022$\n\textension\030\n \003(\013" + "rsion\030\007 \001(\005\022$\n\textension\030\n \003(\0132\021.wallet." +
"2\021.wallet.Extension\022\023\n\013description\030\013 \001(\t", "Extension\022\023\n\013description\030\013 \001(\t\";\n\016Encryp",
"\";\n\016EncryptionType\022\017\n\013UNENCRYPTED\020\001\022\030\n\024E" + "tionType\022\017\n\013UNENCRYPTED\020\001\022\030\n\024ENCRYPTED_S" +
"NCRYPTED_SCRYPT_AES\020\002B\035\n\023org.bitcoinj.wa" + "CRYPT_AES\020\002B\035\n\023org.bitcoinj.walletB\006Prot" +
"lletB\006Protos" "os"
}; };
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {

View File

@ -235,7 +235,6 @@ public class WalletProtobufSerializerTest {
return new WalletProtobufSerializer().readWallet(input); return new WalletProtobufSerializer().readWallet(input);
} }
@Test @Test
public void testRoundTripNormalWallet() throws Exception { public void testRoundTripNormalWallet() throws Exception {
Wallet wallet1 = roundTrip(myWallet); Wallet wallet1 = roundTrip(myWallet);
@ -247,7 +246,22 @@ public class WalletProtobufSerializerTest {
wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getPrivKeyBytes()); wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getPrivKeyBytes());
assertEquals(myKey.getCreationTimeSeconds(), assertEquals(myKey.getCreationTimeSeconds(),
wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getCreationTimeSeconds()); wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getCreationTimeSeconds());
}
@Test
public void coinbaseTxns() throws Exception {
// Covers issue 420 where the outpoint index of a coinbase tx input was being mis-serialized.
Block b = params.getGenesisBlock().createNextBlockWithCoinbase(myKey.getPubKey(), Utils.toNanoCoins(50, 0));
Transaction coinbase = b.getTransactions().get(0);
assertTrue(coinbase.isCoinBase());
BlockChain chain = new BlockChain(params, myWallet, new MemoryBlockStore(params));
assertTrue(chain.add(b));
// Wallet now has a coinbase tx in it.
assertEquals(1, myWallet.getTransactions(true).size());
assertTrue(myWallet.getTransaction(coinbase.getHash()).isCoinBase());
Wallet wallet2 = roundTrip(myWallet);
assertEquals(1, wallet2.getTransactions(true).size());
assertTrue(wallet2.getTransaction(coinbase.getHash()).isCoinBase());
} }
@Test @Test