From: doraemon Date: Tue, 13 Jul 2021 09:42:14 +0000 (+0800) Subject: offine signer X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=44fc5c26e55aefe6f5647f5d637903b060b52a92;p=bytom%2Fbytom-java-sdk.git offine signer --- diff --git a/tx-signer/src/main/java/io/bytom/offline/api/BaseInput.java b/tx-signer/src/main/java/io/bytom/offline/api/BaseInput.java index 6b909a7..bce8182 100644 --- a/tx-signer/src/main/java/io/bytom/offline/api/BaseInput.java +++ b/tx-signer/src/main/java/io/bytom/offline/api/BaseInput.java @@ -11,6 +11,8 @@ public abstract class BaseInput { static final int ISSUANCE_INPUT_TYPE = 0; static final int SPEND_INPUT_TYPE = 1; + static final int Coinbase_INPUT_TYPE = 2; + static final int Veto_INPUT_TYPE = 3; static final byte AssetKeySpace = 0; static final byte AccountKeySpace = 1; @@ -52,7 +54,7 @@ public abstract class BaseInput { public byte[] serializeInput() throws IOException { ByteArrayOutputStream stream = new ByteArrayOutputStream(); - // assert version + // asset version Utils.writeVarint(1, stream); Utils.writeExtensibleString(serializeInputCommitment(), stream); Utils.writeExtensibleString(serializeInputWitness(), stream); @@ -133,4 +135,8 @@ public abstract class BaseInput { public void setKeyIndex(int keyIndex) { this.keyIndex = keyIndex; } + + public void appendWitnessComponent(String witness){ + witnessComponent.appendWitness(witness); + } } diff --git a/tx-signer/src/main/java/io/bytom/offline/api/BaseOutput.java b/tx-signer/src/main/java/io/bytom/offline/api/BaseOutput.java new file mode 100644 index 0000000..e1d9f96 --- /dev/null +++ b/tx-signer/src/main/java/io/bytom/offline/api/BaseOutput.java @@ -0,0 +1,55 @@ +package io.bytom.offline.api; + +import io.bytom.offline.common.Utils; +import io.bytom.offline.types.*; +import org.bouncycastle.util.encoders.Hex; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Map; + +public abstract class BaseOutput { + /** + * The number of units of the asset being controlled. + */ + private Long amount; + + /** + * The id of the asset being controlled. + */ + private String assetId; + + /** + * The control program which must be satisfied to transfer this output. + */ + private String controlProgram; + + /** + * The id of the output. + */ + private String id; + + StateData stateData = new StateData(); + + public BaseOutput() { + } + + public BaseOutput(String assetID, long amount, String controlProgram) { + this.assetId = assetID; + this.amount = amount; + this.controlProgram = controlProgram; + } + + + public abstract byte[] serializeOutputCommitment() throws IOException; + + + public byte[] serializeOutput() throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + // asset version + Utils.writeVarint(1, stream); + Utils.writeExtensibleString(serializeOutputCommitment(), stream); + return stream.toByteArray(); + } + +} \ No newline at end of file diff --git a/tx-signer/src/main/java/io/bytom/offline/api/CoinbaseInput.java b/tx-signer/src/main/java/io/bytom/offline/api/CoinbaseInput.java new file mode 100644 index 0000000..27045a4 --- /dev/null +++ b/tx-signer/src/main/java/io/bytom/offline/api/CoinbaseInput.java @@ -0,0 +1,48 @@ +package io.bytom.offline.api; + +import io.bytom.offline.common.Utils; +import io.bytom.offline.types.*; +import org.bouncycastle.util.encoders.Hex; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Map; + +public class CoinbaseInput extends BaseInput{ + private String arbitrary; + + @Override + public InputEntry toInputEntry(Map entryMap, int index) { + Coinbase coinbase = new Coinbase(arbitrary); + + Hash prevOutID = coinbase.entryID(); + entryMap.put(prevOutID, coinbase); + return new Coinbase(prevOutID,index); + } + + @Override + public void buildWitness(String txID) throws Exception { + + } + + @Override + public byte[] serializeInputCommitment() throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Utils.writeVarint(Coinbase_INPUT_TYPE, stream); + Utils.writeVarStr(Hex.decode(this.arbitrary),stream); + return stream.toByteArray(); + } + + @Override + public byte[] serializeInputWitness() throws IOException { + return new byte[0]; + } + + public String getArbitrary() { + return arbitrary; + } + + public void setArbitrary(String arbitrary) { + this.arbitrary = arbitrary; + } +} diff --git a/tx-signer/src/main/java/io/bytom/offline/api/IssuanceInput.java b/tx-signer/src/main/java/io/bytom/offline/api/IssuanceInput.java index c3b4d16..b13f07b 100644 --- a/tx-signer/src/main/java/io/bytom/offline/api/IssuanceInput.java +++ b/tx-signer/src/main/java/io/bytom/offline/api/IssuanceInput.java @@ -5,6 +5,7 @@ import io.bytom.offline.common.ExpandedPrivateKey; import io.bytom.offline.common.Signer; import io.bytom.offline.common.Utils; import io.bytom.offline.types.*; +import io.bytom.offline.util.AssetIdUtil; import io.bytom.offline.util.SHA3Util; import org.bouncycastle.util.encoders.Hex; import java.io.ByteArrayOutputStream; @@ -18,7 +19,15 @@ public class IssuanceInput extends BaseInput { private String rawAssetDefinition; - public IssuanceInput() {} + public IssuanceInput(){ + + } + + public IssuanceInput(String rawAssetDefinition,String issuanceProgram) { + this.rawAssetDefinition = rawAssetDefinition; + this.setProgram(issuanceProgram); + this.setAssetId(AssetIdUtil.computeAssetID(rawAssetDefinition,issuanceProgram)); + } public IssuanceInput(String assetID, Long amount, String issuanceProgram) { this.setAssetId(assetID); @@ -66,7 +75,10 @@ public class IssuanceInput extends BaseInput { ByteArrayOutputStream stream = new ByteArrayOutputStream(); Utils.writeVarint(ISSUANCE_INPUT_TYPE, stream); Utils.writeVarStr(Hex.decode(nonce), stream); - stream.write(Hex.decode(getAssetId())); + if (this.getAssetId()==null){ + this.setAssetId(AssetIdUtil.computeAssetID(rawAssetDefinition,this.getProgram())); + } + stream.write(Hex.decode(this.getAssetId())); Utils.writeVarint(getAmount(), stream); return stream.toByteArray(); } @@ -84,13 +96,16 @@ public class IssuanceInput extends BaseInput { @Override public void validate() { - super.validate(); if (nonce == null) { throw new IllegalArgumentException("the nonce of issuance input must be specified."); } if (rawAssetDefinition == null) { throw new IllegalArgumentException("the nonce of issuance input must be specified."); } + + if (this.getProgram() == null) { + throw new IllegalArgumentException("the program of issuance must be specified."); + } } public String getNonce() { diff --git a/tx-signer/src/main/java/io/bytom/offline/api/Output.java b/tx-signer/src/main/java/io/bytom/offline/api/OriginalOutput.java similarity index 73% rename from tx-signer/src/main/java/io/bytom/offline/api/Output.java rename to tx-signer/src/main/java/io/bytom/offline/api/OriginalOutput.java index 8f7a2b0..b95c5b6 100644 --- a/tx-signer/src/main/java/io/bytom/offline/api/Output.java +++ b/tx-signer/src/main/java/io/bytom/offline/api/OriginalOutput.java @@ -2,12 +2,12 @@ package io.bytom.offline.api; import io.bytom.offline.common.Utils; import io.bytom.offline.common.VMUtil; +import io.bytom.offline.util.AssetIdUtil; import org.bouncycastle.util.encoders.Hex; import java.io.ByteArrayOutputStream; import java.io.IOException; -public class Output { - +public class OriginalOutput { /** * The number of units of the asset being controlled. */ @@ -28,27 +28,28 @@ public class Output { */ private String id; - /** - * The output's position in a transaction's list of outputs. - */ - private Integer position; + StateData stateData = new StateData(); + + public OriginalOutput() { + } - public Output(String assetID, long amount, String controlProgram) { + public OriginalOutput(String assetID, long amount, String controlProgram) { this.assetId = assetID; this.amount = amount; this.controlProgram = controlProgram; } - public static Output newRetireOutput(String assetID, long amount, String arbitrary) { - String retireProgram = Hex.toHexString(new byte[]{VMUtil.OP_FAIL}) + Hex.toHexString(VMUtil.pushDataBytes(Hex.decode(arbitrary))); - return new Output(assetID, amount, retireProgram); + public OriginalOutput(String rawAssetDefinition,String program) { + this.assetId = AssetIdUtil.computeAssetID(rawAssetDefinition,program); + this.controlProgram = program; } public byte[] serializeOutput() throws IOException { ByteArrayOutputStream stream = new ByteArrayOutputStream(); - - //assetVersion - Utils.writeVarint(1, stream); //AssetVersion是否默认为1 + // asset version + Utils.writeVarint(1, stream); + //outputType + Utils.writeVarint(0, stream); //outputType //outputCommit ByteArrayOutputStream outputCommitSteam = new ByteArrayOutputStream(); //assetId @@ -59,6 +60,8 @@ public class Output { Utils.writeVarint(1, outputCommitSteam); //db中获取vm_version //controlProgram Utils.writeVarStr(Hex.decode(controlProgram), outputCommitSteam); + //stateData + Utils.writeVarList(this.stateData.toByteArray(), outputCommitSteam); Utils.writeExtensibleString(outputCommitSteam.toByteArray(), stream); @@ -67,6 +70,7 @@ public class Output { return stream.toByteArray(); } + public Long getAmount() { return amount; } @@ -99,11 +103,7 @@ public class Output { this.id = id; } - public Integer getPosition() { - return position; - } - - public void setPosition(Integer position) { - this.position = position; + public void appendStateData(String stateDataStr){ + stateData.appendStateData(stateDataStr); } } diff --git a/tx-signer/src/main/java/io/bytom/offline/api/SpendInput.java b/tx-signer/src/main/java/io/bytom/offline/api/SpendInput.java index 0a11c32..1803cde 100644 --- a/tx-signer/src/main/java/io/bytom/offline/api/SpendInput.java +++ b/tx-signer/src/main/java/io/bytom/offline/api/SpendInput.java @@ -19,6 +19,8 @@ public class SpendInput extends BaseInput { private BIPProtocol bipProtocol = BIPProtocol.BIP44; + StateData stateData = new StateData(); + public SpendInput() {} public SpendInput(String assetID, long amount, String controlProgram) { @@ -40,7 +42,7 @@ public class SpendInput extends BaseInput { Hash sourceID = new Hash(this.sourceID); ValueSource src = new ValueSource(sourceID, assetAmount, this.sourcePosition); - OutputEntry prevOut = new OutputEntry(src, pro, 0); + Output prevOut = new Output(src, pro, 0,stateData.toByteArray()); Hash prevOutID = prevOut.entryID(); entryMap.put(prevOutID, prevOut); return new Spend(prevOutID, index); @@ -82,6 +84,7 @@ public class SpendInput extends BaseInput { // vm version Utils.writeVarint(1, spendCommitSteam); Utils.writeVarStr(Hex.decode(getProgram()), spendCommitSteam); + Utils.writeVarList(stateData.toByteArray(), spendCommitSteam); Utils.writeExtensibleString(spendCommitSteam.toByteArray(), stream); return stream.toByteArray(); } @@ -129,4 +132,8 @@ public class SpendInput extends BaseInput { public void setBipProtocol(BIPProtocol bipProtocol) { this.bipProtocol = bipProtocol; } + + public void appendStateData(String stateDataStr){ + stateData.appendStateData(stateDataStr); + } } \ No newline at end of file diff --git a/tx-signer/src/main/java/io/bytom/offline/api/StateData.java b/tx-signer/src/main/java/io/bytom/offline/api/StateData.java new file mode 100644 index 0000000..692dbd9 --- /dev/null +++ b/tx-signer/src/main/java/io/bytom/offline/api/StateData.java @@ -0,0 +1,26 @@ +package io.bytom.offline.api; + +import org.bouncycastle.util.encoders.Hex; + +import java.util.ArrayList; +import java.util.List; + +public class StateData { + private List stateData; + + public StateData() { + stateData = new ArrayList<>(); + } + + public byte[][] toByteArray() { + byte[][] byteArray = new byte[stateData.size()][]; + for (int i = 0; i < stateData.size(); i++) { + byteArray[i] = Hex.decode(stateData.get(i)); + } + return byteArray; + } + + public void appendStateData(String stateDataStr) { + stateData.add(stateDataStr); + } +} diff --git a/tx-signer/src/main/java/io/bytom/offline/api/Transaction.java b/tx-signer/src/main/java/io/bytom/offline/api/Transaction.java index 8798307..9165848 100755 --- a/tx-signer/src/main/java/io/bytom/offline/api/Transaction.java +++ b/tx-signer/src/main/java/io/bytom/offline/api/Transaction.java @@ -41,7 +41,7 @@ public class Transaction { /** * List of specified outputs for a transaction. */ - private List outputs; + private List outputs; public Transaction(Builder builder) { this.inputs = builder.inputs; @@ -64,7 +64,7 @@ public class Transaction { private Integer timeRange; private List inputs; - private List outputs; + private List outputs; public Builder() { this.inputs = new ArrayList<>(); @@ -76,7 +76,7 @@ public class Transaction { return this; } - public Builder addOutput(Output output) { + public Builder addOutput(OriginalOutput output) { this.outputs.add(output); return this; } @@ -86,12 +86,17 @@ public class Transaction { return this; } + public Builder setSize(int size) { + this.size = size; + return this; + } + public Transaction build() { return new Transaction(this); } } - private void sign() { + public void sign() { for (BaseInput input : inputs) { try { input.buildWitness(txID); @@ -117,7 +122,7 @@ public class Transaction { } Utils.writeVarint(outputs.size(), stream); - for (Output output : outputs) { + for (OriginalOutput output : outputs) { stream.write(output.serializeOutput()); } } catch (IOException e) { @@ -167,7 +172,7 @@ public class Transaction { List resultIDList = new ArrayList<>(); for (int i = 0; i < outputs.size(); i++) { - Output output = outputs.get(i); + OriginalOutput output = outputs.get(i); AssetAmount amount = new AssetAmount(new AssetID(output.getAssetId()), output.getAmount()); ValueSource src = new ValueSource(muxID, amount, i); @@ -178,7 +183,7 @@ public class Transaction { resultID = addEntry(entryMap, retirement); } else { Program program = new Program(1, Hex.decode(output.getControlProgram())); - OutputEntry oup = new OutputEntry(src, program, i); + Output oup = new Output(src, program, i,output.stateData.toByteArray()); resultID = addEntry(entryMap, oup); } @@ -225,7 +230,7 @@ public class Transaction { return inputs; } - public List getOutputs() { + public List getOutputs() { return outputs; } } diff --git a/tx-signer/src/main/java/io/bytom/offline/api/VetoInput.java b/tx-signer/src/main/java/io/bytom/offline/api/VetoInput.java new file mode 100644 index 0000000..4119726 --- /dev/null +++ b/tx-signer/src/main/java/io/bytom/offline/api/VetoInput.java @@ -0,0 +1,108 @@ +package io.bytom.offline.api; + +import io.bytom.offline.common.Utils; +import io.bytom.offline.types.*; +import org.bouncycastle.util.encoders.Hex; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Map; + +public class VetoInput extends BaseInput{ + private String sourceID; + + private Integer sourcePosition; + + private Boolean change; + + private Integer controlProgramIndex; + + private byte[] vote; + + StateData stateData = new StateData(); + + @Override + public InputEntry toInputEntry(Map entryMap, int index) { + Program pro = new Program(this.getVmVersion(), Hex.decode(this.getProgram())); + AssetAmount assetAmount = this.getAssetAmount(); + Hash sourceID = new Hash(this.sourceID); + ValueSource src = new ValueSource(sourceID, assetAmount, this.sourcePosition); + + Vote prevOut = new Vote(src, pro, 0,this.vote,stateData.toByteArray()); + Hash prevOutID = prevOut.entryID(); + entryMap.put(prevOutID, prevOut); + return new Veto(prevOutID, index); + } + + @Override + public void buildWitness(String txID) throws Exception { + + } + + @Override + public byte[] serializeInputCommitment() throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Utils.writeVarint(Veto_INPUT_TYPE, stream); + + ByteArrayOutputStream spendCommitSteam = new ByteArrayOutputStream(); + spendCommitSteam.write(Hex.decode(sourceID)); + spendCommitSteam.write(Hex.decode(getAssetId())); + Utils.writeVarint(getAmount(), spendCommitSteam); + Utils.writeVarint(sourcePosition, spendCommitSteam); + // vm version + Utils.writeVarint(1, spendCommitSteam); + Utils.writeVarStr(Hex.decode(getProgram()), spendCommitSteam); + Utils.writeVarList(stateData.toByteArray(), spendCommitSteam); + Utils.writeExtensibleString(spendCommitSteam.toByteArray(), stream); + Utils.writeVarStr(this.vote,stream); + return stream.toByteArray(); + } + + @Override + public byte[] serializeInputWitness() throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Utils.writeVarList(witnessComponent.toByteArray(), stream); + return stream.toByteArray(); + } + + public String getSourceID() { + return sourceID; + } + + public void setSourceID(String sourceID) { + this.sourceID = sourceID; + } + + public Integer getSourcePosition() { + return sourcePosition; + } + + public void setSourcePosition(Integer sourcePosition) { + this.sourcePosition = sourcePosition; + } + + public Boolean getChange() { + return change; + } + + public void setChange(Boolean change) { + this.change = change; + } + + public Integer getControlProgramIndex() { + return controlProgramIndex; + } + + public void setControlProgramIndex(Integer controlProgramIndex) { + this.controlProgramIndex = controlProgramIndex; + } + + public byte[] getVote() { + return vote; + } + + public void setVote(byte[] vote) { + this.vote = vote; + } + +} diff --git a/tx-signer/src/main/java/io/bytom/offline/types/Coinbase.java b/tx-signer/src/main/java/io/bytom/offline/types/Coinbase.java new file mode 100644 index 0000000..94592e9 --- /dev/null +++ b/tx-signer/src/main/java/io/bytom/offline/types/Coinbase.java @@ -0,0 +1,50 @@ +package io.bytom.offline.types; + +import java.io.ByteArrayOutputStream; +import java.util.Map; + +public class Coinbase extends InputEntry{ + private Hash coinbaseOutputID; + + private int ordinal; + + private ValueDestination witnessDestination; + + private String arbitrary; + + public Coinbase(Hash coinbaseOutputID, int ordinal) { + this.coinbaseOutputID = coinbaseOutputID; + this.ordinal = ordinal; + } + + public Coinbase(String arbitrary) { + this.arbitrary = arbitrary; + } + + + @Override + public String typ() { + return "coinbase1"; + } + + @Override + public void writeForHash(ByteArrayOutputStream out) { + System.out.println("write for hash"); + System.out.println(this.arbitrary); + mustWriteForHash(out,this.arbitrary); + } + + @Override + public void setDestination(Hash id, long pos, Map entryMap) { +// OutputEntry spendOutput = (OutputEntry) entryMap.get(this.coinbaseOutputID); +// this.witnessDestination = new ValueDestination(id, spendOutput.getSource().getValue(), pos); + } + + public String getArbitrary() { + return arbitrary; + } + + public void setArbitrary(String arbitrary) { + this.arbitrary = arbitrary; + } +} diff --git a/tx-signer/src/main/java/io/bytom/offline/types/Output.java b/tx-signer/src/main/java/io/bytom/offline/types/Output.java new file mode 100755 index 0000000..a081c97 --- /dev/null +++ b/tx-signer/src/main/java/io/bytom/offline/types/Output.java @@ -0,0 +1,30 @@ +package io.bytom.offline.types; + +import java.io.ByteArrayOutputStream; + +public class Output extends OutputEntry { + public Output() { + this.source = new ValueSource(); + this.controlProgram = new Program(); + } + + + public Output(ValueSource source, Program controlProgram, Integer ordinal, byte[][] stateData) { + this.source = source; + this.controlProgram = controlProgram; + this.ordinal = ordinal; + this.stateData = stateData; + } + + @Override + public String typ() { + return "originalOutput1"; + } + + @Override + public void writeForHash(ByteArrayOutputStream out) { + mustWriteForHash(out, this.source); + mustWriteForHash(out, this.controlProgram); + mustWriteForHash(out, this.stateData); + } +} diff --git a/tx-signer/src/main/java/io/bytom/offline/types/OutputEntry.java b/tx-signer/src/main/java/io/bytom/offline/types/OutputEntry.java index 0d3a83f..6fa2273 100755 --- a/tx-signer/src/main/java/io/bytom/offline/types/OutputEntry.java +++ b/tx-signer/src/main/java/io/bytom/offline/types/OutputEntry.java @@ -2,36 +2,15 @@ package io.bytom.offline.types; import java.io.ByteArrayOutputStream; -public class OutputEntry extends Entry { +public abstract class OutputEntry extends Entry { + protected ValueSource source; - private ValueSource source; + protected Program controlProgram; - private Program controlProgram; + protected Integer ordinal; - private Integer ordinal; + protected byte[][] stateData; - public OutputEntry() { - this.source = new ValueSource(); - this.controlProgram = new Program(); - } - - - public OutputEntry(ValueSource source, Program controlProgram, Integer ordinal) { - this.source = source; - this.controlProgram = controlProgram; - this.ordinal = ordinal; - } - - @Override - public String typ() { - return "output1"; - } - - @Override - public void writeForHash(ByteArrayOutputStream out) { - mustWriteForHash(out, this.source); - mustWriteForHash(out, this.controlProgram); - } public ValueSource getSource() { return source; diff --git a/tx-signer/src/main/java/io/bytom/offline/types/ValueSource.java b/tx-signer/src/main/java/io/bytom/offline/types/ValueSource.java index 4ca1e9c..a6eb672 100755 --- a/tx-signer/src/main/java/io/bytom/offline/types/ValueSource.java +++ b/tx-signer/src/main/java/io/bytom/offline/types/ValueSource.java @@ -11,12 +11,18 @@ public class ValueSource { public ValueSource() {} + public ValueSource(Hash ref, AssetAmount value) { + this.ref = ref; + this.value = value; + } + public ValueSource(Hash ref, AssetAmount value, long position) { this.ref = ref; this.value = value; this.position = position; } + public Hash getRef() { return ref; } diff --git a/tx-signer/src/main/java/io/bytom/offline/types/Veto.java b/tx-signer/src/main/java/io/bytom/offline/types/Veto.java new file mode 100644 index 0000000..d45099b --- /dev/null +++ b/tx-signer/src/main/java/io/bytom/offline/types/Veto.java @@ -0,0 +1,31 @@ +package io.bytom.offline.types; + +import java.io.ByteArrayOutputStream; +import java.util.Map; + +public class Veto extends InputEntry{ + private Hash spentOutputID; + private ValueDestination witnessDestination; + + + public Veto(Hash spentOutputID, int ordinal) { + this.spentOutputID = spentOutputID; + this.ordinal = ordinal; + } + + @Override + public String typ() { + return "vetoInput1"; + } + + @Override + public void writeForHash(ByteArrayOutputStream out) { + mustWriteForHash(out,this.spentOutputID); + } + + @Override + public void setDestination(Hash id, long pos, Map entryMap) { + OutputEntry spendOutput = (OutputEntry) entryMap.get(this.spentOutputID); + this.witnessDestination = new ValueDestination(id, spendOutput.getSource().getValue(), pos); + } +} diff --git a/tx-signer/src/main/java/io/bytom/offline/types/Vote.java b/tx-signer/src/main/java/io/bytom/offline/types/Vote.java new file mode 100644 index 0000000..f12f17a --- /dev/null +++ b/tx-signer/src/main/java/io/bytom/offline/types/Vote.java @@ -0,0 +1,37 @@ +package io.bytom.offline.types; + +import java.io.ByteArrayOutputStream; + +public class Vote extends OutputEntry{ + private byte[] vote; + + public Vote(ValueSource source, Program controlProgram, Integer ordinal,byte[] vote, byte[][] stateData) { + this.source = source; + this.controlProgram = controlProgram; + this.ordinal = ordinal; + this.vote = vote; + this.stateData = stateData; + } + + @Override + public String typ() { + return "voteOutput1"; + } + + @Override + public void writeForHash(ByteArrayOutputStream out) { + mustWriteForHash(out,this.source); + mustWriteForHash(out,this.controlProgram); + mustWriteForHash(out,this.vote); + mustWriteForHash(out,this.stateData); + } + + public byte[] getVote() { + return vote; + } + + public void setVote(byte[] vote) { + this.vote = vote; + } + +} diff --git a/tx-signer/src/main/java/io/bytom/offline/util/AssetIdUtil.java b/tx-signer/src/main/java/io/bytom/offline/util/AssetIdUtil.java new file mode 100644 index 0000000..56b4b7e --- /dev/null +++ b/tx-signer/src/main/java/io/bytom/offline/util/AssetIdUtil.java @@ -0,0 +1,20 @@ +package io.bytom.offline.util; + +import io.bytom.offline.types.AssetDefinition; +import io.bytom.offline.types.Hash; +import io.bytom.offline.types.Program; +import org.bouncycastle.util.encoders.Hex; + +import java.io.ByteArrayOutputStream; + +public class AssetIdUtil { + public static String computeAssetID(String rawAssetDefinition,String controlProgram){ + byte[] hashBytes = SHA3Util.hashSha256(Hex.decode(rawAssetDefinition)); + Hash assetDefHash = new Hash(hashBytes); + Program program = new Program(1,Hex.decode(controlProgram)); + AssetDefinition assetDefinition = new AssetDefinition(assetDefHash, program); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + assetDefinition.writeForHash(out); + return Hex.toHexString(SHA3Util.hashSha256(out.toByteArray())); + } +} diff --git a/tx-signer/src/test/java/io/bytom/offline/api/AppTest.java b/tx-signer/src/test/java/io/bytom/offline/api/AppTest.java deleted file mode 100755 index 6897e92..0000000 --- a/tx-signer/src/test/java/io/bytom/offline/api/AppTest.java +++ /dev/null @@ -1,128 +0,0 @@ -package io.bytom.offline.api; - -import org.junit.Test; - -public class AppTest { - String rootKey = "38d2c44314c401b3ea7c23c54e12c36a527aee46a7f26b82443a46bf40583e439dea25de09b0018b35a741d8cd9f6ec06bc11db49762617485f5309ab72a12d4"; - String btmAssetID = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; - - - @Test - public void testSpendBIP44() { - SpendInput input = new SpendInput(); - input.setAssetId(btmAssetID); - input.setAmount(9800000000L); - input.setProgram("0014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e"); - input.setSourcePosition(2); - input.setSourceID("4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adea"); - input.setChange(true); - input.setControlProgramIndex(457); - input.setKeyIndex(1); - input.setRootPrivateKey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257"); - - Transaction tx = new Transaction.Builder() - .addInput(input) - .addOutput(new Output(btmAssetID, 8800000000L, "0014a82f02bc37bc5ed87d5f9fca02f8a6a7d89cdd5c")) - .addOutput(new Output(btmAssetID, 900000000L, "00200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac66")) - .setTimeRange(0) - .build(); - - String rawTransaction = tx.rawTransaction(); - assert rawTransaction.equals("070100010160015e4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c480c1240201160014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e6302401cb779288be890a28c5209036da1a27d9fe74a51c38e0a10db4817bcf4fd05f68580239eea7dcabf19f144c77bf13d3674b5139aa51a99ba58118386c190af0e20bcbe020b05e1b7d0825953d92bf47897be08cd7751a37adb95d6a2e5224f55ab02013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80b095e42001160014a82f02bc37bc5ed87d5f9fca02f8a6a7d89cdd5c000149ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80d293ad03012200200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac6600"); - } - - @Test - public void testSpendBIP32() { - SpendInput input = new SpendInput(btmAssetID, 11718900000L, "0014085a02ecdf934a56343aa59a3dec9d9feb86ee43"); - input.setSourceID("5ac79a73db78e5c9215b37cb752f0147d1157c542bb4884908ceb97abc33fe0a"); - input.setSourcePosition(0); - input.setRootPrivateKey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257"); - input.setChange(true); - input.setKeyIndex(1); - input.setBipProtocol(BIPProtocol.BIP32); - input.setControlProgramIndex(447); - - Transaction tx = new Transaction.Builder() - .addInput(input) - .addOutput(new Output(btmAssetID, 1718900000L, "001409a0961e9b592a944ca3ded0ef9403fdb25b3793")) - .addOutput(new Output(btmAssetID, 9900000000L, "00145ade29df622cc68d0473aa1a20fb89690451c66e")) - .setTimeRange(0) - .build(); - - String rawTx = tx.rawTransaction(); - assert rawTx.equals("070100010160015e5ac79a73db78e5c9215b37cb752f0147d1157c542bb4884908ceb97abc33fe0affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0f280d42b0001160014085a02ecdf934a56343aa59a3dec9d9feb86ee43630240e37864ef905e943deb97e58b861c97f04f07c1d33b1ce4f1b6edddff0c8956a57d86fc922c45446cd38ea613fc3c9b7d5a2596f3dca7a7212f6da55b9515110420a29601468f08c57ca9c383d28736a9d5c7737cd483126d8db3d85490fe497b3502013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0aad1b3060116001409a0961e9b592a944ca3ded0ef9403fdb25b379300013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8086d8f024011600145ade29df622cc68d0473aa1a20fb89690451c66e00"); - } - - //issue asset - @Test - public void testIssue() { - IssuanceInput issuanceInput = new IssuanceInput(); - issuanceInput.setAssetId("7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad14"); - issuanceInput.setAmount(100000000000L); - issuanceInput.setProgram("ae2054a71277cc162eb3eb21b5bd9fe54402829a53b294deaed91692a2cd8a081f9c5151ad"); - issuanceInput.setNonce("ac9d5a527f5ab00a"); - issuanceInput.setKeyIndex(5); - issuanceInput.setRawAssetDefinition("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"); - issuanceInput.setRootPrivateKey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257"); - - SpendInput spendInput = new SpendInput(btmAssetID, 9800000000L, "0014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e"); - spendInput.setBipProtocol(BIPProtocol.BIP32); - spendInput.setKeyIndex(1); - spendInput.setChange(true); - spendInput.setSourceID("4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adea"); - spendInput.setSourcePosition(2); - spendInput.setControlProgramIndex(457); - spendInput.setRootPrivateKey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257"); - - Transaction tx = new Transaction.Builder() - .addInput(issuanceInput) - .addInput(spendInput) - .addOutput(new Output("7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad14", 100000000000L, "001437e1aec83a4e6587ca9609e4e5aa728db7007449")) - .addOutput(new Output(btmAssetID, 9700000000L, "00148be1104e04734e5edaba5eea2e85793896b77c56")) - .setTimeRange(0) - .build(); - - String rawTx = tx.rawTransaction(); - assert rawTx.equals("0701000201300008ac9d5a527f5ab00a7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad1480d0dbc3f402b001467b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d0125ae2054a71277cc162eb3eb21b5bd9fe54402829a53b294deaed91692a2cd8a081f9c5151ad01401ba3a3f2d3e9887e20da8d43666cc1602bb5421ffea9d2b4d7df9816fc174a43b25fb00db4775b10b679a8b5f8aa28555ebb8fb49f6275d43283daf8f5ac340d0160015e4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c480c1240201160014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e630240341c875fc815dc13ad811c9aa7c7af28a5c78765f77fd5a36dac263278fd605ae0553e34a1e645148370b7b397142ddbcd67ba33483279ab9894169b51e4f101201381d35e235813ad1e62f9a602c82abee90565639cc4573568206b55bcd2aed902013e7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad1480d0dbc3f4020116001437e1aec83a4e6587ca9609e4e5aa728db700744900013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8082a99124011600148be1104e04734e5edaba5eea2e85793896b77c5600"); - } - - - //retire asset - @Test - public void testRetire() { - String arbitrary = "77656c636f6d65efbc8ce6aca2e8bf8ee69da5e588b0e58e9fe5ad90e4b896e7958c"; - String assetId1 = "207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf"; - - SpendInput input1 = new SpendInput(btmAssetID, 289100000L, "0014f1dc52048f439ac7fd74f8106a21da78f00de48f"); - input1.setRootPrivateKey(rootKey); - input1.setChange(true); - input1.setControlProgramIndex(41); - input1.setSourceID("0b2cff11d1d056d95237a5f2d06059e5395e86f60e69c1e8201ea624911c0c65"); - input1.setKeyIndex(1); - input1.setSourcePosition(0); - - SpendInput input2 = new SpendInput(assetId1, 70000000000L, "0014bb8a039726df1b649738e9973db14a4b4fd4becf"); - input2.setRootPrivateKey(rootKey); - input2.setChange(true); - input2.setControlProgramIndex(26); - input2.setSourceID("be0ac837e832c34a02968e54dab4f95cbeceb9fb01cd378310f6ea32219ee29b"); - input2.setKeyIndex(1); - input2.setSourcePosition(1); - - Output output1 = new Output(btmAssetID, 279100000L, "001414d362694eacfa110dc20dec77d610d22340f95b"); - Output output2 = Output.newRetireOutput(assetId1, 10000000000L, arbitrary); - Output output3 = new Output(assetId1, 60000000000L, "0014bb8a039726df1b649738e9973db14a4b4fd4becf"); - - Transaction transaction = new Transaction.Builder() - .addInput(input1) - .addInput(input2) - .addOutput(output1) - .addOutput(output2) - .addOutput(output3) - .setTimeRange(2000000) - .build(); - - String rawTransaction = transaction.rawTransaction(); - assert rawTransaction.equals("070180897a020160015e0b2cff11d1d056d95237a5f2d06059e5395e86f60e69c1e8201ea624911c0c65ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0a1ed89010001160014f1dc52048f439ac7fd74f8106a21da78f00de48f6302401660121218ab96d9f22cce712541ca34c53f4da40450669854341ca9624ad1cf10d1bfc96449fad5406224afd253ccfbdeab683f7ec7f9ee8f45e47a0c58500f2031ecc1bdd5fb9b40016358340b87646ea39faf55c0c105205cfdfdc6184725f40161015fbe0ac837e832c34a02968e54dab4f95cbeceb9fb01cd378310f6ea32219ee29b207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf80f8cce284020101160014bb8a039726df1b649738e9973db14a4b4fd4becf630240d7b7f1c2ca1048fd6798234f2a1e895762f83e802507a008eff52605611b67390a74eaf228b76f5589ff109b2c20eaa65fad6de2e5ab8a25b54267b607df970b20a71547e1064b5edaad92cdce6b0ace832836ba28fdeaf0b83010bed247fe927c03013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f48a85010116001414d362694eacfa110dc20dec77d610d22340f95b00014b207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf80c8afa02501246a2277656c636f6d65efbc8ce6aca2e8bf8ee69da5e588b0e58e9fe5ad90e4b896e7958c00013e207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf80b09dc2df0101160014bb8a039726df1b649738e9973db14a4b4fd4becf00"); - } -} diff --git a/tx-signer/src/test/java/io/bytom/offline/api/TransactionTest.java b/tx-signer/src/test/java/io/bytom/offline/api/TransactionTest.java new file mode 100644 index 0000000..e351a19 --- /dev/null +++ b/tx-signer/src/test/java/io/bytom/offline/api/TransactionTest.java @@ -0,0 +1,74 @@ +package io.bytom.offline.api; + +import io.bytom.offline.util.AssetIdUtil; +import org.junit.Test; + +public class TransactionTest { + String btmAssetID = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + + @Test + public void testIssuance() { + String rawAssetDefinition = "7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022676f6c64222c0a20202271756f72756d223a20312c0a20202272656973737565223a202266616c7365222c0a20202273796d626f6c223a2022474f4c44220a7d"; + String issuanceProgram = "0204bfcda069ae2000cf50143dac994b9cfc1a2c45a4332ecefbbb15824b9f1a537f0b49fd9f44b45151ad"; + System.out.println(AssetIdUtil.computeAssetID(rawAssetDefinition,issuanceProgram)); + IssuanceInput issuanceInput = new IssuanceInput("0541db69c21dc827092ddbc5673f5c1f0a09d3112da2a67c6644ec1be3fa38b3",2543541111111L,"0204bfcda069ae2000cf50143dac994b9cfc1a2c45a4332ecefbbb15824b9f1a537f0b49fd9f44b45151ad"); + issuanceInput.setVmVersion(1); + issuanceInput.setRootPrivateKey("b0cc39f8a4b9539fcc8f05c0df21563155767bfc6f2c4b801738eb831589d84afe549d3a89e8223762445a0f3bea5c192675636846f75f1455c6a23d30a37023"); + issuanceInput.setKeyIndex(3); + issuanceInput.setRawAssetDefinition("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022676f6c64222c0a20202271756f72756d223a20312c0a20202272656973737565223a202266616c7365222c0a20202273796d626f6c223a2022474f4c44220a7d"); + issuanceInput.setNonce(""); + + SpendInput spendInput = new SpendInput(); + spendInput.setAssetId(btmAssetID); + spendInput.setAmount(2853881270l); + spendInput.setSourceID("0b75ee155f60160ac14e038eaf7c67c820d77096a615ab00c1a3d9b52f9f246c"); + spendInput.setSourcePosition(0); + spendInput.setChange(false); + spendInput.setVmVersion(1); + spendInput.setProgram("0014e933e5a0545c63ff2c28eaedb47c831cac3b16cf"); + spendInput.setControlProgramIndex(2); + spendInput.setRootPrivateKey("b0cc39f8a4b9539fcc8f05c0df21563155767bfc6f2c4b801738eb831589d84afe549d3a89e8223762445a0f3bea5c192675636846f75f1455c6a23d30a37023"); + spendInput.setKeyIndex(1); + + OriginalOutput issuanceOutput = new OriginalOutput("0541db69c21dc827092ddbc5673f5c1f0a09d3112da2a67c6644ec1be3fa38b3",2543541111111L,"00145894d753c19d8fccce04db88f54751340ad8ca4f"); + OriginalOutput output = new OriginalOutput(btmAssetID,2753881270L,"0014b0b9455c1f77476b96858927d98e823d680ce889"); + + Transaction tx = new Transaction.Builder() + .addInput(issuanceInput) + .addInput(spendInput) + .addOutput(issuanceOutput) + .addOutput(output) + .setTimeRange(0) + .setSize(0) + .build(); + + String rawTransaction = tx.rawTransaction(); + System.out.println(rawTransaction); + } + + @Test + public void testSpendBIP44() { + SpendInput spendInput = new SpendInput(); + spendInput.setAssetId(btmAssetID); + spendInput.setAmount(2873881270l); + spendInput.setSourceID("6dd143552ff8fde887e65eb7c387ff77265d270dfc76d6488a0185476f66c601"); + spendInput.setSourcePosition(0); + spendInput.setChange(false); + spendInput.setVmVersion(1); + spendInput.setProgram("0014e933e5a0545c63ff2c28eaedb47c831cac3b16cf"); + spendInput.setControlProgramIndex(2); + spendInput.setRootPrivateKey("b0cc39f8a4b9539fcc8f05c0df21563155767bfc6f2c4b801738eb831589d84afe549d3a89e8223762445a0f3bea5c192675636846f75f1455c6a23d30a37023"); + spendInput.setKeyIndex(1); + + + OriginalOutput output = new OriginalOutput(btmAssetID,2773881270l,"0014b0b9455c1f77476b96858927d98e823d680ce889"); + Transaction tx = new Transaction.Builder() + .addInput(spendInput) + .addOutput(output) + .setTimeRange(0) + .setSize(0) + .build(); + System.out.println(tx.rawTransaction()); + System.out.println(tx.getTxID()); + } +} diff --git a/tx-signer/src/test/java/io/bytom/offline/api/TxInputTest.java b/tx-signer/src/test/java/io/bytom/offline/api/TxInputTest.java new file mode 100644 index 0000000..22bfffa --- /dev/null +++ b/tx-signer/src/test/java/io/bytom/offline/api/TxInputTest.java @@ -0,0 +1,147 @@ +package io.bytom.offline.api; + +import com.amazonaws.util.StringUtils; +import com.google.crypto.tink.subtle.Hex; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + +public class TxInputTest { + @Test + public void testSpendInput() throws IOException { + SpendInput input = new SpendInput(); + input.setAssetId("fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a"); + input.setAmount(254354); + input.setSourceID("fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409"); + input.setSourcePosition(3); + input.setVmVersion(1); + input.setProgram(Hex.encode("spendProgram".getBytes())); + input.appendStateData(Hex.encode("stateData".getBytes())); + input.appendWitnessComponent(Hex.encode("arguments1".getBytes())); + input.appendWitnessComponent(Hex.encode("arguments2".getBytes())); + + byte[] serializeInputCommitment = input.serializeInput(); + String wantStr= StringUtils.join("", + "01", // asset version + "5f", // input commitment length + "01", // spend type flag + "5d", // spend commitment length + "fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409", // source id + "fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a", // assetID + "92c30f", // amount + "03", // source position + "01", // vm version + "0c", // spend program length + "7370656e6450726f6772616d", // spend program + "0109", // state length + "737461746544617461", // state + "17", // witness length + "02", // argument array length + "0a", // first argument length + "617267756d656e747331", // first argument data + "0a", // second argument length + "617267756d656e747332" // second argument data + ); + + assertEquals(wantStr,Hex.encode(serializeInputCommitment)); + } + + @Test + public void testIssuanceInput() throws IOException { + IssuanceInput issuanceInput = new IssuanceInput(); + issuanceInput.setAmount(254354L); + issuanceInput.setVmVersion(1); + issuanceInput.setProgram(Hex.encode("issuanceProgram".getBytes())); + issuanceInput.setNonce(Hex.encode("nonce".getBytes())); + issuanceInput.setRawAssetDefinition(Hex.encode("assetDefinition".getBytes())); + issuanceInput.appendWitnessComponent(Hex.encode("arguments1".getBytes())); + issuanceInput.appendWitnessComponent(Hex.encode("arguments2".getBytes())); + + byte[] serializeInputCommitment = issuanceInput.serializeInput(); + String wantStr= StringUtils.join("", + "01", // asset version + "2a", // serialization length + "00", // issuance type flag + "05", // nonce length + "6e6f6e6365", // nonce + "a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf", // assetID + "92c30f", // amount + "38", // input witness length + "0f", // asset definition length + "6173736574446566696e6974696f6e", // asset definition + "01", // vm version + "0f", // issuanceProgram length + "69737375616e636550726f6772616d", // issuance program + "02", // argument array length + "0a", // first argument length + "617267756d656e747331", // first argument data + "0a", // second argument length + "617267756d656e747332" // second argument data + ); + + assertEquals(wantStr,Hex.encode(serializeInputCommitment)); + } + + @Test + public void testVetoInput() throws IOException { + VetoInput vetoInput = new VetoInput(); + vetoInput.setSourceID("fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409"); + vetoInput.setAssetId("fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a"); + vetoInput.setSourcePosition(3); + vetoInput.setAmount(254354L); + vetoInput.setVmVersion(1); + vetoInput.setProgram(Hex.encode("spendProgram".getBytes())); + vetoInput.setVote("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269".getBytes()); + vetoInput.appendWitnessComponent(Hex.encode("arguments1".getBytes())); + vetoInput.appendWitnessComponent(Hex.encode("arguments2".getBytes())); + + + byte[] serializeInputCommitment = vetoInput.serializeInput(); + + String wantStr= StringUtils.join("", + "01", // asset version + "d701", // input commitment length + "03", // veto type flag + "53", // veto commitment length + "fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409", // source id + "fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a", // assetID + "92c30f", // amount + "03", // source position + "01", // vm version + "0c", // veto program length + "7370656e6450726f6772616d", // veto program + "00", // state length + "8001", //xpub length + "6166353934303036613430383337643966303238646161626236643538396466306239313338646165666164353638336535323333633236343632373932313732393461386435333265363038363362636631393636323561333566623863656566666133633039363130656239326463666236353561393437663133323639", //voter xpub + "17", // witness length + "02", // argument array length + "0a", // first argument length + "617267756d656e747331", // first argument data + "0a", // second argument length + "617267756d656e747332" // second argument data + ); + + assertEquals(wantStr,Hex.encode(serializeInputCommitment)); + } + + @Test + public void testCoinbaseInput() throws IOException { + CoinbaseInput coinbaseInput = new CoinbaseInput(); + coinbaseInput.setArbitrary(Hex.encode("arbitrary".getBytes())); + + byte[] serializeInputCommitment = coinbaseInput.serializeInput(); + + String wantStr= StringUtils.join("", + "01", // asset version + "0b", // input commitment length + "02", // coinbase type flag + "09", // arbitrary length + "617262697472617279", // arbitrary data + "00" // witness length + ); + + assertEquals(wantStr,Hex.encode(serializeInputCommitment)); + } +} diff --git a/tx-signer/src/test/java/io/bytom/offline/api/TxOutputTest.java b/tx-signer/src/test/java/io/bytom/offline/api/TxOutputTest.java new file mode 100644 index 0000000..8bd83d2 --- /dev/null +++ b/tx-signer/src/test/java/io/bytom/offline/api/TxOutputTest.java @@ -0,0 +1,58 @@ +package io.bytom.offline.api; + +import com.amazonaws.util.StringUtils; +import com.google.crypto.tink.subtle.Hex; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + +public class TxOutputTest { + String assetID = "81756fdab39a17163b0ce582ee4ee256fb4d1e156c692b997d608a42ecb38d47"; + @Test + public void SerializationOriginalTxOutputTest() throws IOException { + OriginalOutput output = new OriginalOutput(assetID,254354L,Hex.encode("TestSerializationTxOutput".getBytes())); + output.appendStateData(Hex.encode("stateData".getBytes())); + + byte[] serializeOutputCommitment = output.serializeOutput(); + String wantStr= StringUtils.join("", + "01", // asset version + "00", // output type + "49", // serialization length + "81756fdab39a17163b0ce582ee4ee256fb4d1e156c692b997d608a42ecb38d47", // assetID + "92c30f", // amount + "01", // version + "19", // control program length + "5465737453657269616c697a6174696f6e54784f7574707574", // control program + "0109", // state data length + "737461746544617461", // state data + "00" // witness length + ); + + assertEquals(wantStr,Hex.encode(serializeOutputCommitment)); + } + + @Test + public void SerializationVetoOutputTest() throws IOException { + OriginalOutput output = new OriginalOutput(assetID,254354L,Hex.encode("TestSerializationTxOutput".getBytes())); + output.appendStateData(Hex.encode("stateData".getBytes())); + + byte[] serializeOutputCommitment = output.serializeOutput(); + String wantStr= StringUtils.join("", + "01", // asset version + "00", // output type + "49", // serialization length + "81756fdab39a17163b0ce582ee4ee256fb4d1e156c692b997d608a42ecb38d47", // assetID + "92c30f", // amount + "01", // version + "19", // control program length + "5465737453657269616c697a6174696f6e54784f7574707574", // control program + "0109", // state data length + "737461746544617461", // state data + "00" // witness length + ); + + assertEquals(wantStr,Hex.encode(serializeOutputCommitment)); + } +}