Transaction can serialize and deserialize according to Segwit (BIP144). This adds TransactionWitnesses to the wallet protobuf, too.

The goal of this commit is to fix loading blk*.dat files by BlockFileLoader. Bitcoinj cannot yet
create segwit transactions nor does it correctly process them.

Based on code by:
  NicolasDorier <nicolas.dorier@gmail.com>
  Oscar Guindzberg <oscar.guindzberg@gmail.com>
  sstone <sstone@users.noreply.github.com>
This commit is contained in:
Andreas Schildbach 2018-03-05 11:07:39 +01:00
parent 9d6090a7ea
commit 648655da99
13 changed files with 1114 additions and 80 deletions

View file

@ -523,6 +523,7 @@ public abstract class NetworkParameters {
MINIMUM(70000),
PONG(60001),
BLOOM_FILTER(70000),
WITNESS_VERSION(70012),
CURRENT(70012);
private final int bitcoinProtocol;

View file

@ -257,7 +257,13 @@ public class Transaction extends ChildMessage {
@Override
public Sha256Hash getHash() {
if (hash == null) {
hash = Sha256Hash.wrapReversed(Sha256Hash.hashTwice(unsafeBitcoinSerialize()));
ByteArrayOutputStream stream = new UnsafeByteArrayOutputStream(length < 32 ? 32 : length + 32);
try {
bitcoinSerializeToStream(stream, false);
} catch (IOException e) {
// Cannot happen, we are serializing to a memory stream.
}
hash = Sha256Hash.wrapReversed(Sha256Hash.hashTwice(stream.toByteArray()));
}
return hash;
}
@ -563,14 +569,41 @@ public class Transaction extends ChildMessage {
return cursor - offset + 4;
}
/**
* Deserialize according to <a href="https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki">BIP144</a> or
* the <a href="https://en.bitcoin.it/wiki/Protocol_documentation#tx">classic format</a>, depending on if the
* transaction is segwit or not.
*/
@Override
protected void parse() throws ProtocolException {
cursor = offset;
version = readUint32();
optimalEncodingMessageSize = 4;
// First come the inputs.
// version
version = readUint32();
// peek at marker
byte marker = payload[cursor];
boolean useSegwit = marker == 0;
// marker, flag
if (useSegwit) {
readBytes(2);
optimalEncodingMessageSize += 2;
}
// txin_count, txins
parseInputs();
// txout_count, txouts
parseOutputs();
// script_witnesses
if (useSegwit)
parseWitnesses();
// lock_time
lockTime = readUint32();
optimalEncodingMessageSize += 4;
length = cursor - offset;
}
private void parseInputs() {
long numInputs = readVarInt();
optimalEncodingMessageSize += VarInt.sizeOf(numInputs);
inputs = new ArrayList<>(Math.min((int) numInputs, MAX_INITIAL_INPUTS_OUTPUTS_SIZE));
@ -581,7 +614,9 @@ public class Transaction extends ChildMessage {
optimalEncodingMessageSize += TransactionOutPoint.MESSAGE_LENGTH + VarInt.sizeOf(scriptLen) + scriptLen + 4;
cursor += scriptLen + 4;
}
// Now the outputs
}
private void parseOutputs() {
long numOutputs = readVarInt();
optimalEncodingMessageSize += VarInt.sizeOf(numOutputs);
outputs = new ArrayList<>(Math.min((int) numOutputs, MAX_INITIAL_INPUTS_OUTPUTS_SIZE));
@ -592,9 +627,30 @@ public class Transaction extends ChildMessage {
optimalEncodingMessageSize += 8 + VarInt.sizeOf(scriptLen) + scriptLen;
cursor += scriptLen;
}
lockTime = readUint32();
optimalEncodingMessageSize += 4;
length = cursor - offset;
}
private void parseWitnesses() {
int numWitnesses = inputs.size();
for (int i = 0; i < numWitnesses; i++) {
long pushCount = readVarInt();
TransactionWitness witness = new TransactionWitness((int) pushCount);
getInput(i).setWitness(witness);
optimalEncodingMessageSize += VarInt.sizeOf(pushCount);
for (int y = 0; y < pushCount; y++) {
long pushSize = readVarInt();
optimalEncodingMessageSize += VarInt.sizeOf(pushSize) + pushSize;
byte[] push = readBytes((int) pushSize);
witness.setPush(y, push);
}
}
}
/** @return true of the transaction has any witnesses in any of its inputs */
public boolean hasWitnesses() {
for (TransactionInput in : inputs)
if (in.hasWitness())
return true;
return false;
}
public int getOptimalEncodingMessageSize() {
@ -694,6 +750,7 @@ public class Transaction extends ChildMessage {
return s.toString();
}
if (!inputs.isEmpty()) {
int i = 0;
for (TransactionInput in : inputs) {
s.append(" ");
s.append("in ");
@ -704,6 +761,11 @@ public class Transaction extends ChildMessage {
final Coin value = in.getValue();
if (value != null)
s.append(" ").append(value.toFriendlyString());
if (in.hasWitness()) {
s.append("\n ");
s.append("witness:");
s.append(in.getWitness());
}
s.append("\n ");
s.append("outpoint:");
final TransactionOutPoint outpoint = in.getOutpoint();
@ -730,6 +792,7 @@ public class Transaction extends ChildMessage {
s.append("[exception: ").append(e.getMessage()).append("]");
}
s.append('\n');
i++;
}
} else {
s.append(" ");
@ -1129,17 +1192,42 @@ public class Transaction extends ChildMessage {
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
boolean useSegwit = hasWitnesses()
&& protocolVersion >= NetworkParameters.ProtocolVersion.WITNESS_VERSION.getBitcoinProtocolVersion();
bitcoinSerializeToStream(stream, useSegwit);
}
/**
* Serialize according to <a href="https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki">BIP144</a> or the
* <a href="https://en.bitcoin.it/wiki/Protocol_documentation#tx">classic format</a>, depending on if segwit is
* desired.
*/
protected void bitcoinSerializeToStream(OutputStream stream, boolean useSegwit) throws IOException {
// version
uint32ToByteStreamLE(version, stream);
// marker, flag
if (useSegwit) {
stream.write(0);
stream.write(1);
}
// txin_count, txins
stream.write(new VarInt(inputs.size()).encode());
for (TransactionInput in : inputs)
in.bitcoinSerialize(stream);
// txout_count, txouts
stream.write(new VarInt(outputs.size()).encode());
for (TransactionOutput out : outputs)
out.bitcoinSerialize(stream);
// script_witnisses
if (useSegwit) {
for (TransactionInput in : inputs) {
in.getWitness().bitcoinSerializeToStream(stream);
}
}
// lock_time
uint32ToByteStreamLE(lockTime, stream);
}
/**
* Transactions can have an associated lock time, specified either as a block height or in seconds since the
* UNIX epoch. A transaction is not allowed to be confirmed by miners until the lock time is reached, and

View file

@ -81,6 +81,8 @@ public class TransactionInput extends ChildMessage {
@Nullable
private Coin value;
private TransactionWitness witness;
/**
* Creates an input that connects to nothing - used only in creation of coinbase transactions.
*/
@ -265,6 +267,31 @@ public class TransactionInput extends ChildMessage {
return value;
}
/**
* Get the transaction witness of this input.
*
* @return the witness of the input
*/
public TransactionWitness getWitness() {
return witness != null ? witness : TransactionWitness.EMPTY;
}
/**
* Set the transaction witness of an input.
*/
public void setWitness(TransactionWitness witness) {
this.witness = witness;
}
/**
* Determine if the transaction has witnesses.
*
* @return true if the transaction has witnesses
*/
public boolean hasWitness() {
return witness != null && witness.getPushCount() != 0;
}
public enum ConnectionResult {
NO_SUCH_TX,
ALREADY_SPENT,
@ -501,7 +528,7 @@ public class TransactionInput extends ChildMessage {
s.append(": COINBASE");
} else {
s.append(" for [").append(outpoint).append("]: ").append(getScriptSig());
String flags = Joiner.on(", ").skipNulls().join(
String flags = Joiner.on(", ").skipNulls().join(hasWitness() ? "witness" : null,
hasSequence() ? "sequence: " + Long.toHexString(sequence) : null,
isOptInFullRBF() ? "opts into full RBF" : null);
if (!flags.isEmpty())

View file

@ -0,0 +1,79 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TransactionWitness {
public static final TransactionWitness EMPTY = new TransactionWitness(0);
private final byte[][] pushes;
public TransactionWitness(int pushCount) {
pushes = new byte[pushCount][];
}
public byte[] getPush(int i) {
return pushes[i];
}
public int getPushCount() {
return pushes.length;
}
public void setPush(int i, byte[] value) {
pushes[i] = value;
}
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(new VarInt(pushes.length).encode());
for (int i = 0; i < pushes.length; i++) {
byte[] push = pushes[i];
stream.write(new VarInt(push.length).encode());
stream.write(push);
}
}
@Override
public String toString() {
List<String> stringPushes = new ArrayList<>();
for (int j = 0; j < this.getPushCount(); j++) {
byte[] push = this.getPush(j);
if (push != null) {
stringPushes.add(Utils.HEX.encode(push));
} else {
stringPushes.add("NULL");
}
}
return Utils.SPACE_JOINER.join(stringPushes);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TransactionWitness other = (TransactionWitness) o;
return Arrays.deepEquals(pushes, other.pushes);
}
@Override
public int hashCode() {
return Arrays.deepHashCode(pushes);
}
}

View file

@ -5037,6 +5037,470 @@ public final class Protos {
// @@protoc_insertion_point(class_scope:wallet.Script)
}
public interface ScriptWitnessOrBuilder extends
// @@protoc_insertion_point(interface_extends:wallet.ScriptWitness)
com.google.protobuf.MessageOrBuilder {
/**
* <code>repeated bytes data = 1;</code>
*/
java.util.List<com.google.protobuf.ByteString> getDataList();
/**
* <code>repeated bytes data = 1;</code>
*/
int getDataCount();
/**
* <code>repeated bytes data = 1;</code>
*/
com.google.protobuf.ByteString getData(int index);
}
/**
* Protobuf type {@code wallet.ScriptWitness}
*/
public static final class ScriptWitness extends
com.google.protobuf.GeneratedMessage implements
// @@protoc_insertion_point(message_implements:wallet.ScriptWitness)
ScriptWitnessOrBuilder {
// Use ScriptWitness.newBuilder() to construct.
private ScriptWitness(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
super(builder);
this.unknownFields = builder.getUnknownFields();
}
private ScriptWitness(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
private static final ScriptWitness defaultInstance;
public static ScriptWitness getDefaultInstance() {
return defaultInstance;
}
public ScriptWitness getDefaultInstanceForType() {
return defaultInstance;
}
private final com.google.protobuf.UnknownFieldSet unknownFields;
@java.lang.Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return this.unknownFields;
}
private ScriptWitness(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
initFields();
int mutable_bitField0_ = 0;
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder();
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
default: {
if (!parseUnknownField(input, unknownFields,
extensionRegistry, tag)) {
done = true;
}
break;
}
case 10: {
if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
data_ = new java.util.ArrayList<com.google.protobuf.ByteString>();
mutable_bitField0_ |= 0x00000001;
}
data_.add(input.readBytes());
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(
e.getMessage()).setUnfinishedMessage(this);
} finally {
if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
data_ = java.util.Collections.unmodifiableList(data_);
}
this.unknownFields = unknownFields.build();
makeExtensionsImmutable();
}
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return org.bitcoinj.wallet.Protos.internal_static_wallet_ScriptWitness_descriptor;
}
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return org.bitcoinj.wallet.Protos.internal_static_wallet_ScriptWitness_fieldAccessorTable
.ensureFieldAccessorsInitialized(
org.bitcoinj.wallet.Protos.ScriptWitness.class, org.bitcoinj.wallet.Protos.ScriptWitness.Builder.class);
}
public static com.google.protobuf.Parser<ScriptWitness> PARSER =
new com.google.protobuf.AbstractParser<ScriptWitness>() {
public ScriptWitness parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return new ScriptWitness(input, extensionRegistry);
}
};
@java.lang.Override
public com.google.protobuf.Parser<ScriptWitness> getParserForType() {
return PARSER;
}
public static final int DATA_FIELD_NUMBER = 1;
private java.util.List<com.google.protobuf.ByteString> data_;
/**
* <code>repeated bytes data = 1;</code>
*/
public java.util.List<com.google.protobuf.ByteString>
getDataList() {
return data_;
}
/**
* <code>repeated bytes data = 1;</code>
*/
public int getDataCount() {
return data_.size();
}
/**
* <code>repeated bytes data = 1;</code>
*/
public com.google.protobuf.ByteString getData(int index) {
return data_.get(index);
}
private void initFields() {
data_ = java.util.Collections.emptyList();
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized == 1) return true;
if (isInitialized == 0) return false;
memoizedIsInitialized = 1;
return true;
}
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
getSerializedSize();
for (int i = 0; i < data_.size(); i++) {
output.writeBytes(1, data_.get(i));
}
getUnknownFields().writeTo(output);
}
private int memoizedSerializedSize = -1;
public int getSerializedSize() {
int size = memoizedSerializedSize;
if (size != -1) return size;
size = 0;
{
int dataSize = 0;
for (int i = 0; i < data_.size(); i++) {
dataSize += com.google.protobuf.CodedOutputStream
.computeBytesSizeNoTag(data_.get(i));
}
size += dataSize;
size += 1 * getDataList().size();
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
}
private static final long serialVersionUID = 0L;
@java.lang.Override
protected java.lang.Object writeReplace()
throws java.io.ObjectStreamException {
return super.writeReplace();
}
public static org.bitcoinj.wallet.Protos.ScriptWitness parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static org.bitcoinj.wallet.Protos.ScriptWitness parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static org.bitcoinj.wallet.Protos.ScriptWitness parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static org.bitcoinj.wallet.Protos.ScriptWitness parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static org.bitcoinj.wallet.Protos.ScriptWitness parseFrom(java.io.InputStream input)
throws java.io.IOException {
return PARSER.parseFrom(input);
}
public static org.bitcoinj.wallet.Protos.ScriptWitness parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return PARSER.parseFrom(input, extensionRegistry);
}
public static org.bitcoinj.wallet.Protos.ScriptWitness parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return PARSER.parseDelimitedFrom(input);
}
public static org.bitcoinj.wallet.Protos.ScriptWitness parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return PARSER.parseDelimitedFrom(input, extensionRegistry);
}
public static org.bitcoinj.wallet.Protos.ScriptWitness parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return PARSER.parseFrom(input);
}
public static org.bitcoinj.wallet.Protos.ScriptWitness parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return PARSER.parseFrom(input, extensionRegistry);
}
public static Builder newBuilder() { return Builder.create(); }
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder(org.bitcoinj.wallet.Protos.ScriptWitness prototype) {
return newBuilder().mergeFrom(prototype);
}
public Builder toBuilder() { return newBuilder(this); }
@java.lang.Override
protected Builder newBuilderForType(
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* Protobuf type {@code wallet.ScriptWitness}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessage.Builder<Builder> implements
// @@protoc_insertion_point(builder_implements:wallet.ScriptWitness)
org.bitcoinj.wallet.Protos.ScriptWitnessOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return org.bitcoinj.wallet.Protos.internal_static_wallet_ScriptWitness_descriptor;
}
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return org.bitcoinj.wallet.Protos.internal_static_wallet_ScriptWitness_fieldAccessorTable
.ensureFieldAccessorsInitialized(
org.bitcoinj.wallet.Protos.ScriptWitness.class, org.bitcoinj.wallet.Protos.ScriptWitness.Builder.class);
}
// Construct using org.bitcoinj.wallet.Protos.ScriptWitness.newBuilder()
private Builder() {
maybeForceBuilderInitialization();
}
private Builder(
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
super(parent);
maybeForceBuilderInitialization();
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
}
}
private static Builder create() {
return new Builder();
}
public Builder clear() {
super.clear();
data_ = java.util.Collections.emptyList();
bitField0_ = (bitField0_ & ~0x00000001);
return this;
}
public Builder clone() {
return create().mergeFrom(buildPartial());
}
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return org.bitcoinj.wallet.Protos.internal_static_wallet_ScriptWitness_descriptor;
}
public org.bitcoinj.wallet.Protos.ScriptWitness getDefaultInstanceForType() {
return org.bitcoinj.wallet.Protos.ScriptWitness.getDefaultInstance();
}
public org.bitcoinj.wallet.Protos.ScriptWitness build() {
org.bitcoinj.wallet.Protos.ScriptWitness result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
public org.bitcoinj.wallet.Protos.ScriptWitness buildPartial() {
org.bitcoinj.wallet.Protos.ScriptWitness result = new org.bitcoinj.wallet.Protos.ScriptWitness(this);
int from_bitField0_ = bitField0_;
if (((bitField0_ & 0x00000001) == 0x00000001)) {
data_ = java.util.Collections.unmodifiableList(data_);
bitField0_ = (bitField0_ & ~0x00000001);
}
result.data_ = data_;
onBuilt();
return result;
}
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof org.bitcoinj.wallet.Protos.ScriptWitness) {
return mergeFrom((org.bitcoinj.wallet.Protos.ScriptWitness)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(org.bitcoinj.wallet.Protos.ScriptWitness other) {
if (other == org.bitcoinj.wallet.Protos.ScriptWitness.getDefaultInstance()) return this;
if (!other.data_.isEmpty()) {
if (data_.isEmpty()) {
data_ = other.data_;
bitField0_ = (bitField0_ & ~0x00000001);
} else {
ensureDataIsMutable();
data_.addAll(other.data_);
}
onChanged();
}
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
public final boolean isInitialized() {
return true;
}
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
org.bitcoinj.wallet.Protos.ScriptWitness parsedMessage = null;
try {
parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
parsedMessage = (org.bitcoinj.wallet.Protos.ScriptWitness) e.getUnfinishedMessage();
throw e;
} finally {
if (parsedMessage != null) {
mergeFrom(parsedMessage);
}
}
return this;
}
private int bitField0_;
private java.util.List<com.google.protobuf.ByteString> data_ = java.util.Collections.emptyList();
private void ensureDataIsMutable() {
if (!((bitField0_ & 0x00000001) == 0x00000001)) {
data_ = new java.util.ArrayList<com.google.protobuf.ByteString>(data_);
bitField0_ |= 0x00000001;
}
}
/**
* <code>repeated bytes data = 1;</code>
*/
public java.util.List<com.google.protobuf.ByteString>
getDataList() {
return java.util.Collections.unmodifiableList(data_);
}
/**
* <code>repeated bytes data = 1;</code>
*/
public int getDataCount() {
return data_.size();
}
/**
* <code>repeated bytes data = 1;</code>
*/
public com.google.protobuf.ByteString getData(int index) {
return data_.get(index);
}
/**
* <code>repeated bytes data = 1;</code>
*/
public Builder setData(
int index, com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
ensureDataIsMutable();
data_.set(index, value);
onChanged();
return this;
}
/**
* <code>repeated bytes data = 1;</code>
*/
public Builder addData(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
ensureDataIsMutable();
data_.add(value);
onChanged();
return this;
}
/**
* <code>repeated bytes data = 1;</code>
*/
public Builder addAllData(
java.lang.Iterable<? extends com.google.protobuf.ByteString> values) {
ensureDataIsMutable();
com.google.protobuf.AbstractMessageLite.Builder.addAll(
values, data_);
onChanged();
return this;
}
/**
* <code>repeated bytes data = 1;</code>
*/
public Builder clearData() {
data_ = java.util.Collections.emptyList();
bitField0_ = (bitField0_ & ~0x00000001);
onChanged();
return this;
}
// @@protoc_insertion_point(builder_scope:wallet.ScriptWitness)
}
static {
defaultInstance = new ScriptWitness(true);
defaultInstance.initFields();
}
// @@protoc_insertion_point(class_scope:wallet.ScriptWitness)
}
public interface TransactionInputOrBuilder extends
// @@protoc_insertion_point(interface_extends:wallet.TransactionInput)
com.google.protobuf.MessageOrBuilder {
@ -5125,6 +5589,31 @@ public final class Protos {
* </pre>
*/
long getValue();
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
boolean hasWitness();
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
org.bitcoinj.wallet.Protos.ScriptWitness getWitness();
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
org.bitcoinj.wallet.Protos.ScriptWitnessOrBuilder getWitnessOrBuilder();
}
/**
* Protobuf type {@code wallet.TransactionInput}
@ -5203,6 +5692,19 @@ public final class Protos {
value_ = input.readInt64();
break;
}
case 50: {
org.bitcoinj.wallet.Protos.ScriptWitness.Builder subBuilder = null;
if (((bitField0_ & 0x00000020) == 0x00000020)) {
subBuilder = witness_.toBuilder();
}
witness_ = input.readMessage(org.bitcoinj.wallet.Protos.ScriptWitness.PARSER, extensionRegistry);
if (subBuilder != null) {
subBuilder.mergeFrom(witness_);
witness_ = subBuilder.buildPartial();
}
bitField0_ |= 0x00000020;
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
@ -5358,12 +5860,46 @@ public final class Protos {
return value_;
}
public static final int WITNESS_FIELD_NUMBER = 6;
private org.bitcoinj.wallet.Protos.ScriptWitness witness_;
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
public boolean hasWitness() {
return ((bitField0_ & 0x00000020) == 0x00000020);
}
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
public org.bitcoinj.wallet.Protos.ScriptWitness getWitness() {
return witness_;
}
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
public org.bitcoinj.wallet.Protos.ScriptWitnessOrBuilder getWitnessOrBuilder() {
return witness_;
}
private void initFields() {
transactionOutPointHash_ = com.google.protobuf.ByteString.EMPTY;
transactionOutPointIndex_ = 0;
scriptBytes_ = com.google.protobuf.ByteString.EMPTY;
sequence_ = 0;
value_ = 0L;
witness_ = org.bitcoinj.wallet.Protos.ScriptWitness.getDefaultInstance();
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@ -5405,6 +5941,9 @@ public final class Protos {
if (((bitField0_ & 0x00000010) == 0x00000010)) {
output.writeInt64(5, value_);
}
if (((bitField0_ & 0x00000020) == 0x00000020)) {
output.writeMessage(6, witness_);
}
getUnknownFields().writeTo(output);
}
@ -5434,6 +5973,10 @@ public final class Protos {
size += com.google.protobuf.CodedOutputStream
.computeInt64Size(5, value_);
}
if (((bitField0_ & 0x00000020) == 0x00000020)) {
size += com.google.protobuf.CodedOutputStream
.computeMessageSize(6, witness_);
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@ -5543,6 +6086,7 @@ public final class Protos {
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
getWitnessFieldBuilder();
}
}
private static Builder create() {
@ -5561,6 +6105,12 @@ public final class Protos {
bitField0_ = (bitField0_ & ~0x00000008);
value_ = 0L;
bitField0_ = (bitField0_ & ~0x00000010);
if (witnessBuilder_ == null) {
witness_ = org.bitcoinj.wallet.Protos.ScriptWitness.getDefaultInstance();
} else {
witnessBuilder_.clear();
}
bitField0_ = (bitField0_ & ~0x00000020);
return this;
}
@ -5609,6 +6159,14 @@ public final class Protos {
to_bitField0_ |= 0x00000010;
}
result.value_ = value_;
if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
to_bitField0_ |= 0x00000020;
}
if (witnessBuilder_ == null) {
result.witness_ = witness_;
} else {
result.witness_ = witnessBuilder_.build();
}
result.bitField0_ = to_bitField0_;
onBuilt();
return result;
@ -5640,6 +6198,9 @@ public final class Protos {
if (other.hasValue()) {
setValue(other.getValue());
}
if (other.hasWitness()) {
mergeWitness(other.getWitness());
}
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@ -5925,6 +6486,158 @@ public final class Protos {
return this;
}
private org.bitcoinj.wallet.Protos.ScriptWitness witness_ = org.bitcoinj.wallet.Protos.ScriptWitness.getDefaultInstance();
private com.google.protobuf.SingleFieldBuilder<
org.bitcoinj.wallet.Protos.ScriptWitness, org.bitcoinj.wallet.Protos.ScriptWitness.Builder, org.bitcoinj.wallet.Protos.ScriptWitnessOrBuilder> witnessBuilder_;
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
public boolean hasWitness() {
return ((bitField0_ & 0x00000020) == 0x00000020);
}
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
public org.bitcoinj.wallet.Protos.ScriptWitness getWitness() {
if (witnessBuilder_ == null) {
return witness_;
} else {
return witnessBuilder_.getMessage();
}
}
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
public Builder setWitness(org.bitcoinj.wallet.Protos.ScriptWitness value) {
if (witnessBuilder_ == null) {
if (value == null) {
throw new NullPointerException();
}
witness_ = value;
onChanged();
} else {
witnessBuilder_.setMessage(value);
}
bitField0_ |= 0x00000020;
return this;
}
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
public Builder setWitness(
org.bitcoinj.wallet.Protos.ScriptWitness.Builder builderForValue) {
if (witnessBuilder_ == null) {
witness_ = builderForValue.build();
onChanged();
} else {
witnessBuilder_.setMessage(builderForValue.build());
}
bitField0_ |= 0x00000020;
return this;
}
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
public Builder mergeWitness(org.bitcoinj.wallet.Protos.ScriptWitness value) {
if (witnessBuilder_ == null) {
if (((bitField0_ & 0x00000020) == 0x00000020) &&
witness_ != org.bitcoinj.wallet.Protos.ScriptWitness.getDefaultInstance()) {
witness_ =
org.bitcoinj.wallet.Protos.ScriptWitness.newBuilder(witness_).mergeFrom(value).buildPartial();
} else {
witness_ = value;
}
onChanged();
} else {
witnessBuilder_.mergeFrom(value);
}
bitField0_ |= 0x00000020;
return this;
}
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
public Builder clearWitness() {
if (witnessBuilder_ == null) {
witness_ = org.bitcoinj.wallet.Protos.ScriptWitness.getDefaultInstance();
onChanged();
} else {
witnessBuilder_.clear();
}
bitField0_ = (bitField0_ & ~0x00000020);
return this;
}
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
public org.bitcoinj.wallet.Protos.ScriptWitness.Builder getWitnessBuilder() {
bitField0_ |= 0x00000020;
onChanged();
return getWitnessFieldBuilder().getBuilder();
}
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
public org.bitcoinj.wallet.Protos.ScriptWitnessOrBuilder getWitnessOrBuilder() {
if (witnessBuilder_ != null) {
return witnessBuilder_.getMessageOrBuilder();
} else {
return witness_;
}
}
/**
* <code>optional .wallet.ScriptWitness witness = 6;</code>
*
* <pre>
* script witness
* </pre>
*/
private com.google.protobuf.SingleFieldBuilder<
org.bitcoinj.wallet.Protos.ScriptWitness, org.bitcoinj.wallet.Protos.ScriptWitness.Builder, org.bitcoinj.wallet.Protos.ScriptWitnessOrBuilder>
getWitnessFieldBuilder() {
if (witnessBuilder_ == null) {
witnessBuilder_ = new com.google.protobuf.SingleFieldBuilder<
org.bitcoinj.wallet.Protos.ScriptWitness, org.bitcoinj.wallet.Protos.ScriptWitness.Builder, org.bitcoinj.wallet.Protos.ScriptWitnessOrBuilder>(
getWitness(),
getParentForChildren(),
isClean());
witness_ = null;
}
return witnessBuilder_;
}
// @@protoc_insertion_point(builder_scope:wallet.TransactionInput)
}
@ -18014,6 +18727,11 @@ public final class Protos {
private static
com.google.protobuf.GeneratedMessage.FieldAccessorTable
internal_static_wallet_Script_fieldAccessorTable;
private static final com.google.protobuf.Descriptors.Descriptor
internal_static_wallet_ScriptWitness_descriptor;
private static
com.google.protobuf.GeneratedMessage.FieldAccessorTable
internal_static_wallet_ScriptWitness_fieldAccessorTable;
private static final com.google.protobuf.Descriptors.Descriptor
internal_static_wallet_TransactionInput_descriptor;
private static
@ -18088,64 +18806,66 @@ public final class Protos {
"INAL\020\001\022\030\n\024ENCRYPTED_SCRYPT_AES\020\002\022\032\n\026DETE" +
"RMINISTIC_MNEMONIC\020\003\022\025\n\021DETERMINISTIC_KE" +
"Y\020\004\"5\n\006Script\022\017\n\007program\030\001 \002(\014\022\032\n\022creati",
"on_timestamp\030\002 \002(\003\"\222\001\n\020TransactionInput\022" +
"\"\n\032transaction_out_point_hash\030\001 \002(\014\022#\n\033t" +
"ransaction_out_point_index\030\002 \002(\r\022\024\n\014scri" +
"pt_bytes\030\003 \002(\014\022\020\n\010sequence\030\004 \001(\r\022\r\n\005valu" +
"e\030\005 \001(\003\"\177\n\021TransactionOutput\022\r\n\005value\030\001 " +
"\002(\003\022\024\n\014script_bytes\030\002 \002(\014\022!\n\031spent_by_tr" +
"ansaction_hash\030\003 \001(\014\022\"\n\032spent_by_transac" +
"tion_index\030\004 \001(\005\"\267\003\n\025TransactionConfiden" +
"ce\0220\n\004type\030\001 \001(\0162\".wallet.TransactionCon" +
"fidence.Type\022\032\n\022appeared_at_height\030\002 \001(\005",
"\022\036\n\026overriding_transaction\030\003 \001(\014\022\r\n\005dept" +
"h\030\004 \001(\005\022)\n\014broadcast_by\030\006 \003(\0132\023.wallet.P" +
"eerAddress\022\033\n\023last_broadcasted_at\030\010 \001(\003\022" +
"4\n\006source\030\007 \001(\0162$.wallet.TransactionConf" +
"idence.Source\"`\n\004Type\022\013\n\007UNKNOWN\020\000\022\014\n\010BU" +
"ILDING\020\001\022\013\n\007PENDING\020\002\022\025\n\021NOT_IN_BEST_CHA" +
"IN\020\003\022\010\n\004DEAD\020\004\022\017\n\013IN_CONFLICT\020\005\"A\n\006Sourc" +
"e\022\022\n\016SOURCE_UNKNOWN\020\000\022\022\n\016SOURCE_NETWORK\020" +
"\001\022\017\n\013SOURCE_SELF\020\002\"\303\005\n\013Transaction\022\017\n\007ve" +
"rsion\030\001 \002(\005\022\014\n\004hash\030\002 \002(\014\022&\n\004pool\030\003 \001(\0162",
"\030.wallet.Transaction.Pool\022\021\n\tlock_time\030\004" +
" \001(\r\022\022\n\nupdated_at\030\005 \001(\003\0223\n\021transaction_" +
"input\030\006 \003(\0132\030.wallet.TransactionInput\0225\n" +
"\022transaction_output\030\007 \003(\0132\031.wallet.Trans" +
"actionOutput\022\022\n\nblock_hash\030\010 \003(\014\022 \n\030bloc" +
"k_relativity_offsets\030\013 \003(\005\0221\n\nconfidence" +
"\030\t \001(\0132\035.wallet.TransactionConfidence\0225\n" +
"\007purpose\030\n \001(\0162\033.wallet.Transaction.Purp" +
"ose:\007UNKNOWN\022+\n\rexchange_rate\030\014 \001(\0132\024.wa" +
"llet.ExchangeRate\022\014\n\004memo\030\r \001(\t\"Y\n\004Pool\022",
"\013\n\007UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002\022\010\n" +
"\004DEAD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_INACTIVE" +
"\020\022\"\243\001\n\007Purpose\022\013\n\007UNKNOWN\020\000\022\020\n\014USER_PAYM" +
"ENT\020\001\022\020\n\014KEY_ROTATION\020\002\022\034\n\030ASSURANCE_CON" +
"TRACT_CLAIM\020\003\022\035\n\031ASSURANCE_CONTRACT_PLED" +
"GE\020\004\022\033\n\027ASSURANCE_CONTRACT_STUB\020\005\022\r\n\tRAI" +
"SE_FEE\020\006\"N\n\020ScryptParameters\022\014\n\004salt\030\001 \002" +
"(\014\022\020\n\001n\030\002 \001(\003:\00516384\022\014\n\001r\030\003 \001(\005:\0018\022\014\n\001p\030" +
"\004 \001(\005:\0011\"8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004dat" +
"a\030\002 \002(\014\022\021\n\tmandatory\030\003 \002(\010\" \n\003Tag\022\013\n\003tag",
"\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\"\261\004\n\006Wallet\022\032\n\022netwo" +
"rk_identifier\030\001 \002(\t\022\034\n\024last_seen_block_h" +
"ash\030\002 \001(\014\022\036\n\026last_seen_block_height\030\014 \001(" +
"\r\022!\n\031last_seen_block_time_secs\030\016 \001(\003\022\030\n\003" +
"key\030\003 \003(\0132\013.wallet.Key\022(\n\013transaction\030\004 " +
"\003(\0132\023.wallet.Transaction\022&\n\016watched_scri" +
"pt\030\017 \003(\0132\016.wallet.Script\022C\n\017encryption_t" +
"ype\030\005 \001(\0162\035.wallet.Wallet.EncryptionType" +
":\013UNENCRYPTED\0227\n\025encryption_parameters\030\006" +
" \001(\0132\030.wallet.ScryptParameters\022\022\n\007versio",
"n\030\007 \001(\005:\0011\022$\n\textension\030\n \003(\0132\021.wallet.E" +
"xtension\022\023\n\013description\030\013 \001(\t\022\031\n\021key_rot" +
"ation_time\030\r \001(\004\022\031\n\004tags\030\020 \003(\0132\013.wallet." +
"Tag\";\n\016EncryptionType\022\017\n\013UNENCRYPTED\020\001\022\030" +
"\n\024ENCRYPTED_SCRYPT_AES\020\002\"R\n\014ExchangeRate" +
"\022\022\n\ncoin_value\030\001 \002(\003\022\022\n\nfiat_value\030\002 \002(\003" +
"\022\032\n\022fiat_currency_code\030\003 \002(\tB\035\n\023org.bitc" +
"oinj.walletB\006Protos"
"on_timestamp\030\002 \002(\003\"\035\n\rScriptWitness\022\014\n\004d" +
"ata\030\001 \003(\014\"\272\001\n\020TransactionInput\022\"\n\032transa" +
"ction_out_point_hash\030\001 \002(\014\022#\n\033transactio" +
"n_out_point_index\030\002 \002(\r\022\024\n\014script_bytes\030" +
"\003 \002(\014\022\020\n\010sequence\030\004 \001(\r\022\r\n\005value\030\005 \001(\003\022&" +
"\n\007witness\030\006 \001(\0132\025.wallet.ScriptWitness\"\177" +
"\n\021TransactionOutput\022\r\n\005value\030\001 \002(\003\022\024\n\014sc" +
"ript_bytes\030\002 \002(\014\022!\n\031spent_by_transaction" +
"_hash\030\003 \001(\014\022\"\n\032spent_by_transaction_inde" +
"x\030\004 \001(\005\"\267\003\n\025TransactionConfidence\0220\n\004typ",
"e\030\001 \001(\0162\".wallet.TransactionConfidence.T" +
"ype\022\032\n\022appeared_at_height\030\002 \001(\005\022\036\n\026overr" +
"iding_transaction\030\003 \001(\014\022\r\n\005depth\030\004 \001(\005\022)" +
"\n\014broadcast_by\030\006 \003(\0132\023.wallet.PeerAddres" +
"s\022\033\n\023last_broadcasted_at\030\010 \001(\003\0224\n\006source" +
"\030\007 \001(\0162$.wallet.TransactionConfidence.So" +
"urce\"`\n\004Type\022\013\n\007UNKNOWN\020\000\022\014\n\010BUILDING\020\001\022" +
"\013\n\007PENDING\020\002\022\025\n\021NOT_IN_BEST_CHAIN\020\003\022\010\n\004D" +
"EAD\020\004\022\017\n\013IN_CONFLICT\020\005\"A\n\006Source\022\022\n\016SOUR" +
"CE_UNKNOWN\020\000\022\022\n\016SOURCE_NETWORK\020\001\022\017\n\013SOUR",
"CE_SELF\020\002\"\303\005\n\013Transaction\022\017\n\007version\030\001 \002" +
"(\005\022\014\n\004hash\030\002 \002(\014\022&\n\004pool\030\003 \001(\0162\030.wallet." +
"Transaction.Pool\022\021\n\tlock_time\030\004 \001(\r\022\022\n\nu" +
"pdated_at\030\005 \001(\003\0223\n\021transaction_input\030\006 \003" +
"(\0132\030.wallet.TransactionInput\0225\n\022transact" +
"ion_output\030\007 \003(\0132\031.wallet.TransactionOut" +
"put\022\022\n\nblock_hash\030\010 \003(\014\022 \n\030block_relativ" +
"ity_offsets\030\013 \003(\005\0221\n\nconfidence\030\t \001(\0132\035." +
"wallet.TransactionConfidence\0225\n\007purpose\030" +
"\n \001(\0162\033.wallet.Transaction.Purpose:\007UNKN",
"OWN\022+\n\rexchange_rate\030\014 \001(\0132\024.wallet.Exch" +
"angeRate\022\014\n\004memo\030\r \001(\t\"Y\n\004Pool\022\013\n\007UNSPEN" +
"T\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002\022\010\n\004DEAD\020\n\022\013" +
"\n\007PENDING\020\020\022\024\n\020PENDING_INACTIVE\020\022\"\243\001\n\007Pu" +
"rpose\022\013\n\007UNKNOWN\020\000\022\020\n\014USER_PAYMENT\020\001\022\020\n\014" +
"KEY_ROTATION\020\002\022\034\n\030ASSURANCE_CONTRACT_CLA" +
"IM\020\003\022\035\n\031ASSURANCE_CONTRACT_PLEDGE\020\004\022\033\n\027A" +
"SSURANCE_CONTRACT_STUB\020\005\022\r\n\tRAISE_FEE\020\006\"" +
"N\n\020ScryptParameters\022\014\n\004salt\030\001 \002(\014\022\020\n\001n\030\002" +
" \001(\003:\00516384\022\014\n\001r\030\003 \001(\005:\0018\022\014\n\001p\030\004 \001(\005:\0011\"",
"8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\022\021" +
"\n\tmandatory\030\003 \002(\010\" \n\003Tag\022\013\n\003tag\030\001 \002(\t\022\014\n" +
"\004data\030\002 \002(\014\"\261\004\n\006Wallet\022\032\n\022network_identi" +
"fier\030\001 \002(\t\022\034\n\024last_seen_block_hash\030\002 \001(\014" +
"\022\036\n\026last_seen_block_height\030\014 \001(\r\022!\n\031last" +
"_seen_block_time_secs\030\016 \001(\003\022\030\n\003key\030\003 \003(\013" +
"2\013.wallet.Key\022(\n\013transaction\030\004 \003(\0132\023.wal" +
"let.Transaction\022&\n\016watched_script\030\017 \003(\0132" +
"\016.wallet.Script\022C\n\017encryption_type\030\005 \001(\016" +
"2\035.wallet.Wallet.EncryptionType:\013UNENCRY",
"PTED\0227\n\025encryption_parameters\030\006 \001(\0132\030.wa" +
"llet.ScryptParameters\022\022\n\007version\030\007 \001(\005:\001" +
"1\022$\n\textension\030\n \003(\0132\021.wallet.Extension\022" +
"\023\n\013description\030\013 \001(\t\022\031\n\021key_rotation_tim" +
"e\030\r \001(\004\022\031\n\004tags\030\020 \003(\0132\013.wallet.Tag\";\n\016En" +
"cryptionType\022\017\n\013UNENCRYPTED\020\001\022\030\n\024ENCRYPT" +
"ED_SCRYPT_AES\020\002\"R\n\014ExchangeRate\022\022\n\ncoin_" +
"value\030\001 \002(\003\022\022\n\nfiat_value\030\002 \002(\003\022\032\n\022fiat_" +
"currency_code\030\003 \002(\tB\035\n\023org.bitcoinj.wall" +
"etB\006Protos"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
@ -18189,56 +18909,62 @@ public final class Protos {
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_Script_descriptor,
new java.lang.String[] { "Program", "CreationTimestamp", });
internal_static_wallet_TransactionInput_descriptor =
internal_static_wallet_ScriptWitness_descriptor =
getDescriptor().getMessageTypes().get(5);
internal_static_wallet_ScriptWitness_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_ScriptWitness_descriptor,
new java.lang.String[] { "Data", });
internal_static_wallet_TransactionInput_descriptor =
getDescriptor().getMessageTypes().get(6);
internal_static_wallet_TransactionInput_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_TransactionInput_descriptor,
new java.lang.String[] { "TransactionOutPointHash", "TransactionOutPointIndex", "ScriptBytes", "Sequence", "Value", });
new java.lang.String[] { "TransactionOutPointHash", "TransactionOutPointIndex", "ScriptBytes", "Sequence", "Value", "Witness", });
internal_static_wallet_TransactionOutput_descriptor =
getDescriptor().getMessageTypes().get(6);
getDescriptor().getMessageTypes().get(7);
internal_static_wallet_TransactionOutput_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_TransactionOutput_descriptor,
new java.lang.String[] { "Value", "ScriptBytes", "SpentByTransactionHash", "SpentByTransactionIndex", });
internal_static_wallet_TransactionConfidence_descriptor =
getDescriptor().getMessageTypes().get(7);
getDescriptor().getMessageTypes().get(8);
internal_static_wallet_TransactionConfidence_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_TransactionConfidence_descriptor,
new java.lang.String[] { "Type", "AppearedAtHeight", "OverridingTransaction", "Depth", "BroadcastBy", "LastBroadcastedAt", "Source", });
internal_static_wallet_Transaction_descriptor =
getDescriptor().getMessageTypes().get(8);
getDescriptor().getMessageTypes().get(9);
internal_static_wallet_Transaction_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_Transaction_descriptor,
new java.lang.String[] { "Version", "Hash", "Pool", "LockTime", "UpdatedAt", "TransactionInput", "TransactionOutput", "BlockHash", "BlockRelativityOffsets", "Confidence", "Purpose", "ExchangeRate", "Memo", });
internal_static_wallet_ScryptParameters_descriptor =
getDescriptor().getMessageTypes().get(9);
getDescriptor().getMessageTypes().get(10);
internal_static_wallet_ScryptParameters_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_ScryptParameters_descriptor,
new java.lang.String[] { "Salt", "N", "R", "P", });
internal_static_wallet_Extension_descriptor =
getDescriptor().getMessageTypes().get(10);
getDescriptor().getMessageTypes().get(11);
internal_static_wallet_Extension_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_Extension_descriptor,
new java.lang.String[] { "Id", "Data", "Mandatory", });
internal_static_wallet_Tag_descriptor =
getDescriptor().getMessageTypes().get(11);
getDescriptor().getMessageTypes().get(12);
internal_static_wallet_Tag_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_Tag_descriptor,
new java.lang.String[] { "Tag", "Data", });
internal_static_wallet_Wallet_descriptor =
getDescriptor().getMessageTypes().get(12);
getDescriptor().getMessageTypes().get(13);
internal_static_wallet_Wallet_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_Wallet_descriptor,
new java.lang.String[] { "NetworkIdentifier", "LastSeenBlockHash", "LastSeenBlockHeight", "LastSeenBlockTimeSecs", "Key", "Transaction", "WatchedScript", "EncryptionType", "EncryptionParameters", "Version", "Extension", "Description", "KeyRotationTime", "Tags", });
internal_static_wallet_ExchangeRate_descriptor =
getDescriptor().getMessageTypes().get(13);
getDescriptor().getMessageTypes().get(14);
internal_static_wallet_ExchangeRate_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_ExchangeRate_descriptor,

View file

@ -28,6 +28,7 @@ import org.bitcoinj.core.TransactionConfidence.ConfidenceType;
import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutPoint;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.TransactionWitness;
import org.bitcoinj.crypto.KeyCrypter;
import org.bitcoinj.crypto.KeyCrypterScrypt;
import org.bitcoinj.script.Script;
@ -275,6 +276,14 @@ public class WalletProtobufSerializer {
inputBuilder.setSequence((int) input.getSequenceNumber());
if (input.getValue() != null)
inputBuilder.setValue(input.getValue().value);
if (input.hasWitness()) {
TransactionWitness witness = input.getWitness();
Protos.ScriptWitness.Builder witnessBuilder = Protos.ScriptWitness.newBuilder();
int pushCount = witness.getPushCount();
for (int i = 0; i < pushCount; i++)
witnessBuilder.addData(ByteString.copyFrom(witness.getPush(i)));
inputBuilder.setWitness(witnessBuilder);
}
txBuilder.addTransactionInput(inputBuilder);
}
@ -640,6 +649,15 @@ public class WalletProtobufSerializer {
TransactionInput input = new TransactionInput(params, tx, scriptBytes, outpoint, value);
if (inputProto.hasSequence())
input.setSequenceNumber(0xffffffffL & inputProto.getSequence());
if (inputProto.hasWitness()) {
Protos.ScriptWitness witnessProto = inputProto.getWitness();
if (witnessProto.getDataCount() > 0) {
TransactionWitness witness = new TransactionWitness(witnessProto.getDataCount());
for (int j = 0; j < witnessProto.getDataCount(); j++)
witness.setPush(j, witnessProto.getData(j).toByteArray());
input.setWitness(witness);
}
}
tx.addInput(input);
}

View file

@ -147,6 +147,10 @@ message Script {
required int64 creation_timestamp = 2;
}
message ScriptWitness {
repeated bytes data = 1;
}
message TransactionInput {
// Hash of the transaction this input is using.
required bytes transaction_out_point_hash = 1;
@ -158,6 +162,8 @@ message TransactionInput {
optional uint32 sequence = 4;
// Value of connected output, if known
optional int64 value = 5;
// script witness
optional ScriptWitness witness = 6;
}
message TransactionOutput {

View file

@ -257,6 +257,13 @@ public class BlockTest {
ScriptPattern.extractSegwitCommitmentHash(segwitCommitment).toString());
}
@Test
public void testBlock481829_segwitTransaction() throws Exception {
Block block481829 = MAINNET.getDefaultSerializer()
.makeBlock(ByteStreams.toByteArray(getClass().getResourceAsStream("block481829.dat")));
assertEquals(2020, block481829.getTransactions().size());
}
@Test
public void isBIPs() throws Exception {
final Block genesis = MAINNET.getGenesisBlock();

View file

@ -66,7 +66,7 @@ public class TransactionBroadcastTest extends TestWithPeerGroup {
@Test
public void fourPeers() throws Exception {
InboundMessageQueuer[] channels = { connectPeer(1), connectPeer(2), connectPeer(3), connectPeer(4) };
Transaction tx = new Transaction(UNITTEST);
Transaction tx = FakeTxBuilder.createFakeTx(UNITTEST);
tx.getConfidence().setSource(TransactionConfidence.Source.SELF);
TransactionBroadcast broadcast = new TransactionBroadcast(peerGroup, tx);
final AtomicDouble lastProgress = new AtomicDouble();
@ -127,7 +127,7 @@ public class TransactionBroadcastTest extends TestWithPeerGroup {
@Test
public void rejectHandling() throws Exception {
InboundMessageQueuer[] channels = { connectPeer(0), connectPeer(1), connectPeer(2), connectPeer(3), connectPeer(4) };
Transaction tx = new Transaction(UNITTEST);
Transaction tx = FakeTxBuilder.createFakeTx(UNITTEST);
TransactionBroadcast broadcast = new TransactionBroadcast(peerGroup, tx);
ListenableFuture<Transaction> future = broadcast.broadcast();
// 0 and 3 are randomly selected to receive the broadcast.

View file

@ -269,6 +269,39 @@ public class TransactionTest {
} catch (ScriptException e) { }
}
@Test
public void witnessTransaction() {
String hex = null;
String hex2 = null;
Transaction tx = null;
// Roundtrip without witness
hex = "0100000003362c10b042d48378b428d60c5c98d8b8aca7a03e1a2ca1048bfd469934bbda95010000008b483045022046c8bc9fb0e063e2fc8c6b1084afe6370461c16cbf67987d97df87827917d42d022100c807fa0ab95945a6e74c59838cc5f9e850714d8850cec4db1e7f3bcf71d5f5ef0141044450af01b4cc0d45207bddfb47911744d01f768d23686e9ac784162a5b3a15bc01e6653310bdd695d8c35d22e9bb457563f8de116ecafea27a0ec831e4a3e9feffffffffc19529a54ae15c67526cc5e20e535973c2d56ef35ff51bace5444388331c4813000000008b48304502201738185959373f04cc73dbbb1d061623d51dc40aac0220df56dabb9b80b72f49022100a7f76bde06369917c214ee2179e583fefb63c95bf876eb54d05dfdf0721ed772014104e6aa2cf108e1c650e12d8dd7ec0a36e478dad5a5d180585d25c30eb7c88c3df0c6f5fd41b3e70b019b777abd02d319bf724de184001b3d014cb740cb83ed21a6ffffffffbaae89b5d2e3ca78fd3f13cf0058784e7c089fb56e1e596d70adcfa486603967010000008b483045022055efbaddb4c67c1f1a46464c8f770aab03d6b513779ad48735d16d4c5b9907c2022100f469d50a5e5556fc2c932645f6927ac416aa65bc83d58b888b82c3220e1f0b73014104194b3f8aa08b96cae19b14bd6c32a92364bea3051cb9f018b03e3f09a57208ff058f4b41ebf96b9911066aef3be22391ac59175257af0984d1432acb8f2aefcaffffffff0340420f00000000001976a914c0fbb13eb10b57daa78b47660a4ffb79c29e2e6b88ac204e0000000000001976a9142cae94ffdc05f8214ccb2b697861c9c07e3948ee88ac1c2e0100000000001976a9146e03561cd4d6033456cc9036d409d2bf82721e9888ac00000000";
tx = new Transaction(NetworkParameters.fromID(NetworkParameters.ID_MAINNET), HEX.decode(hex));
assertFalse(tx.hasWitnesses());
assertEquals(3, tx.getInputs().size());
for (TransactionInput in : tx.getInputs())
assertFalse(in.hasWitness());
assertEquals(3, tx.getOutputs().size());
hex2 = HEX.encode(tx.bitcoinSerialize());
assertEquals(hex, hex2);
assertEquals("Uncorrect hash", "38d4cfeb57d6685753b7a3b3534c3cb576c34ca7344cd4582f9613ebf0c2b02a",
tx.getHash().toString());
// Roundtrip with witness
hex = "0100000000010213206299feb17742091c3cb2ab45faa3aa87922d3c030cafb3f798850a2722bf0000000000feffffffa12f2424b9599898a1d30f06e1ce55eba7fabfeee82ae9356f07375806632ff3010000006b483045022100fcc8cf3014248e1a0d6dcddf03e80f7e591605ad0dbace27d2c0d87274f8cd66022053fcfff64f35f22a14deb657ac57f110084fb07bb917c3b42e7d033c54c7717b012102b9e4dcc33c9cc9cb5f42b96dddb3b475b067f3e21125f79e10c853e5ca8fba31feffffff02206f9800000000001976a9144841b9874d913c430048c78a7b18baebdbea440588ac8096980000000000160014e4873ef43eac347471dd94bc899c51b395a509a502483045022100dd8250f8b5c2035d8feefae530b10862a63030590a851183cb61b3672eb4f26e022057fe7bc8593f05416c185d829b574290fb8706423451ebd0a0ae50c276b87b43012102179862f40b85fa43487500f1d6b13c864b5eb0a83999738db0f7a6b91b2ec64f00db080000";
tx = new Transaction(NetworkParameters.fromID(NetworkParameters.ID_MAINNET), HEX.decode(hex));
assertTrue(tx.hasWitnesses());
assertEquals(2, tx.getInputs().size());
assertTrue(tx.getInput(0).hasWitness());
assertFalse(tx.getInput(1).hasWitness());
assertEquals(2, tx.getOutputs().size());
hex2 = HEX.encode(tx.bitcoinSerialize());
assertEquals(hex, hex2);
assertEquals("Uncorrect hash", "99e7484eafb6e01622c395c8cae7cb9f8822aab6ba993696b39df8b60b0f4b11",
tx.getHash().toString());
}
@Test
public void testToStringWhenLockTimeIsSpecifiedInBlockHeight() {
Transaction tx = FakeTxBuilder.createFakeTx(UNITTEST);

View file

@ -0,0 +1,36 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import static org.junit.Assert.*;
import org.junit.Test;
public class TransactionWitnessTest {
@Test
public void testToString() throws Exception {
TransactionWitness w1 = new TransactionWitness(0);
assertEquals("", w1.toString());
TransactionWitness w2 = new TransactionWitness(2);
assertEquals("NULL NULL", w2.toString());
TransactionWitness w3 = new TransactionWitness(3);
w3.setPush(0, Utils.HEX.decode("123aaa"));
w3.setPush(1, Utils.HEX.decode("123bbb"));
w3.setPush(2, Utils.HEX.decode("123ccc"));
assertEquals("123aaa 123bbb 123ccc", w3.toString());
}
}

View file

@ -471,4 +471,17 @@ public class WalletProtobufSerializerTest {
proto.setVersion(2);
new WalletProtobufSerializer().readWallet(UNITTEST, null, proto.build());
}
@Test
public void storeWitnessTransactions() throws Exception {
// 3 inputs, inputs 0 and 2 have witnesses but not input 1
Transaction tx = new Transaction(UNITTEST, Utils.HEX.decode(
"02000000000103fc8a5bea59392369e8a1b635395e507a5cbaeffd926e6967a00d17c669aef1d3010000001716001403c80a334ed6a92cf400d8c708522ea0d6fa5593ffffffffc0166d2218a2613b5384fc2c31238b1b6fa337080a1384220734e1bfd3629d3f0100000000ffffffffc0166d2218a2613b5384fc2c31238b1b6fa337080a1384220734e1bfd3629d3f0200000000ffffffff01a086010000000000220020eb72e573a9513d982a01f0e6a6b53e92764db81a0c26d2be94c5fc5b69a0db7d02473044022048e895b7af715303ce273a2be03d6110ed69b5700679f4f036000f8ba6eddd2802205f780423fcce9b3632ed41681b0a86f5d123766b71f303558c39c1be5fe43e2601210259eb16169df80dbe5856d082a226d84a97d191c895f8046c3544df525028a874000220c0166d2218a2613b5384fc2c31238b1b6fa337080a1384220734e1bfd3629d3f20c0166d2218a2613b5384fc2c31238b1b6fa337080a1384220734e1bfd3629d3f00000000"));
assertTrue(tx.hasWitnesses());
assertEquals(tx.getHashAsString(), "1c687396f4710f26206dbdd8bf07a28c76398be6750226ddfaf05a1a80d30034");
myWallet.addWalletTransaction(new WalletTransaction(Pool.UNSPENT, tx));
Wallet wallet1 = roundTrip(myWallet);
Transaction tx2 = wallet1.getTransaction(tx.getHash());
assertEquals(tx.getInput(0).getWitness(), tx2.getInput(0).getWitness());
}
}