<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <maven.compiler.target>1.8</maven.compiler.target>
+ <maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
public abstract class BaseInput {
- public static final int ISSUANCE_INPUT_TYPE = 0;
- public static final int SPEND_INPUT_TYPE = 1;
+ static final int ISSUANCE_INPUT_TYPE = 0;
+ static final int SPEND_INPUT_TYPE = 1;
+
+ static final byte AssetKeySpace = 0;
+ static final byte AccountKeySpace = 1;
private String inputID;
/**
* The number of units of the asset being issued or spent.
*/
- private long amount;
+ private Long amount;
/**
* The id of the asset being issued or spent.
/**
* The program which must be satisfied to transfer this output.
+ * it represents control program when is SpendInput, it represents issuance program when is IssuanceInput
*/
private String program;
- private int vmVersion;
+ private int vmVersion = 1;
- private int keyIndex;
+ /**
+ * used for bip32 derived path.
+ * it represents accountIndex when is SpendInput, it represents assetIndex when is IssuanceInput
+ */
+ private Integer keyIndex;
- private WitnessComponent witnessComponent = new WitnessComponent();
+ WitnessComponent witnessComponent = new WitnessComponent();
- public BaseInput() {
- this.vmVersion = 1;
- }
+ public BaseInput() {}
public abstract InputEntry convertInputEntry(Map<Hash, Entry> entryMap, int index);
-
public abstract byte[] serializeInput() throws IOException;
-
public abstract void buildWitness(String txID) throws Exception;
+ public void validate() {
+ if (assetId == null) {
+ throw new IllegalArgumentException("the asset id of input must be specified.");
+ }
+ if (amount == null) {
+ throw new IllegalArgumentException("the amount id of input must be specified.");
+ }
+ if (program == null) {
+ throw new IllegalArgumentException("the program id of input must be specified.");
+ }
+ if (witnessComponent.getRootPrivateKey() == null) {
+ throw new IllegalArgumentException("the root private key of input must be specified.");
+ }
+ }
+
@Override
public String toString() {
return Utils.serializer.toJson(this);
return inputID;
}
- public int getKeyIndex() {
- return keyIndex;
+ public void setInputID(String inputID) {
+ this.inputID = inputID;
}
- public int getVmVersion() {
- return vmVersion;
+ public long getAmount() {
+ return amount;
}
- public String getProgram() {
- return program;
+ public void setAmount(long amount) {
+ this.amount = amount;
}
public String getAssetId() {
return assetId;
}
- public long getAmount() {
- return amount;
+ public void setAssetId(String assetId) {
+ this.assetId = assetId;
}
- public void setInputID(String inputID) {
- this.inputID = inputID;
+ public String getProgram() {
+ return program;
}
- public void setAmount(long amount) {
- this.amount = amount;
+ public void setProgram(String program) {
+ this.program = program;
}
- public void setAssetId(String assetId) {
- this.assetId = assetId;
+ public int getVmVersion() {
+ return vmVersion;
}
- public void setProgram(String program) {
- this.program = program;
+ public void setVmVersion(int vmVersion) {
+ this.vmVersion = vmVersion;
}
- public void setKeyIndex(int keyIndex) {
- this.keyIndex = keyIndex;
+ public int getKeyIndex() {
+ return keyIndex;
}
- public WitnessComponent getWitnessComponent() {
- return witnessComponent;
+ public void setKeyIndex(int keyIndex) {
+ this.keyIndex = keyIndex;
}
}
import io.bytom.common.DerivePrivateKey;
import io.bytom.common.ExpandedPrivateKey;
+import io.bytom.common.Signer;
import io.bytom.common.Utils;
import io.bytom.types.*;
import io.bytom.util.SHA3Util;
private String nonce;
- private String assetDefinition;
+ private String rawAssetDefinition;
public IssuanceInput() {}
+ public IssuanceInput(String assetID, Long amount, String issuanceProgram) {
+ this.setAssetId(assetID);
+ this.setAmount(amount);
+ this.setProgram(issuanceProgram);
+ }
+
+ public IssuanceInput(String assetID, Long amount, String issuanceProgram, String nonce, String rawAssetDefinition) {
+ this(assetID, amount, issuanceProgram);
+ this.nonce = nonce;
+ this.rawAssetDefinition = rawAssetDefinition;
+ }
+
@Override
public InputEntry convertInputEntry(Map<Hash, Entry> entryMap, int index) {
if (this.nonce == null) {
}
Hash nonceHash = new Hash(SHA3Util.hashSha256(Hex.decode(this.nonce)));
- Hash assetDefHash = new Hash(this.assetDefinition);
+ Hash assetDefHash = new Hash(this.rawAssetDefinition);
AssetAmount value = this.getAssetAmount();
Issue issuance = new Issue(nonceHash, value, index);
//未知
Utils.writeVarint(1, issueInfo1);
//写入assetDefine
- Utils.writeVarStr(Hex.decode(assetDefinition), issueInfo1);
+ Utils.writeVarStr(Hex.decode(rawAssetDefinition), issueInfo1);
//vm.version
Utils.writeVarint(1, issueInfo1);
//controlProgram
Utils.writeVarStr(Hex.decode(getProgram()), issueInfo1);
//inputWitness
- if (null != getWitnessComponent()) {
- ByteArrayOutputStream witnessStream = new ByteArrayOutputStream();
- //arguments
- int witnessSize = getWitnessComponent().size();
- //arguments的length
- Utils.writeVarint(witnessSize, witnessStream);
- for (int i = 0; i < witnessSize; i++) {
- String witness = getWitnessComponent().getWitness(i);
- Utils.writeVarStr(Hex.decode(witness), witnessStream);
- }
- issueInfo1.write(witnessStream.toByteArray());
+ ByteArrayOutputStream witnessStream = new ByteArrayOutputStream();
+ //arguments
+ int witnessSize = witnessComponent.size();
+ //arguments的length
+ Utils.writeVarint(witnessSize, witnessStream);
+ for (int i = 0; i < witnessSize; i++) {
+ String witness = witnessComponent.getWitness(i);
+ Utils.writeVarStr(Hex.decode(witness), witnessStream);
}
+ issueInfo1.write(witnessStream.toByteArray());
stream.write(issueInfo1.toByteArray().length - 1);
stream.write(issueInfo1.toByteArray());
return stream.toByteArray();
@Override
public void buildWitness(String txID) throws Exception {
- String rootPrivateKey = getWitnessComponent().getRootPrivateKey();
- byte[] childPrivateKey = DerivePrivateKey.bip32derivePrvKey(rootPrivateKey, getKeyIndex(), TransactionSigner.AssetKeySpace);
+ String rootPrivateKey = witnessComponent.getRootPrivateKey();
+ byte[] childPrivateKey = DerivePrivateKey.bip32derivePrvKey(rootPrivateKey, getKeyIndex(), AssetKeySpace);
byte[] message = Utils.hashFn(Hex.decode(getInputID()), Hex.decode(txID));
byte[] expandedPrivateKey = ExpandedPrivateKey.expandedPrivateKey(childPrivateKey);
byte[] sig = Signer.ed25519InnerSign(expandedPrivateKey, message);
- getWitnessComponent().appendWitness(Hex.toHexString(sig));
+ witnessComponent.appendWitness(Hex.toHexString(sig));
+ }
+
+ @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.");
+ }
+ }
+
+ public String getNonce() {
+ return nonce;
}
public void setNonce(String nonce) {
this.nonce = nonce;
}
- public void setAssetDefinition(String assetDefinition) {
- this.assetDefinition = assetDefinition;
+ public String getRawAssetDefinition() {
+ return rawAssetDefinition;
+ }
+
+ public void setRawAssetDefinition(String rawAssetDefinition) {
+ this.rawAssetDefinition = rawAssetDefinition;
}
}
import org.bouncycastle.util.encoders.Hex;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.util.Map;
public class Output {
/**
- * address
- */
- public String address;
-
- /**
* The number of units of the asset being controlled.
*/
- public long amount;
-
- /**
- * The definition of the asset being controlled (possibly null).
- */
- public Map<String, Object> assetDefinition;
+ public Long amount;
/**
* The id of the asset being controlled.
*/
public Integer position;
- public Output(String assetId, long amount, String controlProgram) {
+ public Output(String assetId, Long amount, String controlProgram) {
this.assetId = assetId;
this.amount = amount;
this.controlProgram = controlProgram;
return stream.toByteArray();
}
- /**
- * The type the output.<br>
- * Possible values are "control" and "retire".
- */
- public String type;
-
- public Output setAddress(String address) {
- this.address = address;
- return this;
+ public Long getAmount() {
+ return amount;
}
- public Output setAmount(long amount) {
+ public void setAmount(Long amount) {
this.amount = amount;
- return this;
}
- public Output setAssetId(String assetId) {
+ public String getAssetId() {
+ return assetId;
+ }
+
+ public void setAssetId(String assetId) {
this.assetId = assetId;
- return this;
}
- public Output setControlProgram(String controlProgram) {
+ public String getControlProgram() {
+ return controlProgram;
+ }
+
+ public void setControlProgram(String controlProgram) {
this.controlProgram = controlProgram;
- return this;
}
- public Output setPosition(Integer position) {
+ public String getId() {
+ return id;
+ }
+
+ public Integer getPosition() {
+ return position;
+ }
+
+ public void setPosition(Integer position) {
this.position = position;
- return this;
}
}
public class SpendInput extends BaseInput {
- private String sourceId;
+ private String sourceID;
- private long sourcePosition;
+ private Integer sourcePosition;
- private boolean change;
+ private Boolean change;
- private int controlProgramIndex;
+ private Integer controlProgramIndex;
- private BIPProtocol bipProtocol;
+ private BIPProtocol bipProtocol = BIPProtocol.BIP44;
public SpendInput() {}
this.setAssetId(assetID);
this.setAmount(amount);
this.setProgram(controlProgram);
- this.bipProtocol = BIPProtocol.BIP44;
+ }
+
+ public SpendInput(String assetID, long amount, String controlProgram, String sourceID, Integer sourcePosition) {
+ this(assetID, amount, controlProgram);
+ this.sourceID = sourceID;
+ this.sourcePosition = sourcePosition;
}
@Override
public InputEntry convertInputEntry(Map<Hash, Entry> entryMap, int index) {
Program pro = new Program(this.getVmVersion(), Hex.decode(this.getProgram()));
AssetAmount assetAmount = this.getAssetAmount();
- Hash sourceID = new Hash(this.sourceId);
+ Hash sourceID = new Hash(this.sourceID);
ValueSource src = new ValueSource(sourceID, assetAmount, this.sourcePosition);
OutputEntry prevout = new OutputEntry(src, pro, 0);
Utils.writeVarint(SPEND_INPUT_TYPE, inputCommitStream);
//spendCommitment
ByteArrayOutputStream spendCommitSteam = new ByteArrayOutputStream();
- spendCommitSteam.write(Hex.decode(sourceId)); //计算muxID
+ spendCommitSteam.write(Hex.decode(sourceID)); //计算muxID
spendCommitSteam.write(Hex.decode(getAssetId()));
Utils.writeVarint(getAmount(), spendCommitSteam);
//sourcePosition
stream.write(dataInputCommit);
//inputWitness
- if (null != getWitnessComponent()) {
- ByteArrayOutputStream witnessStream = new ByteArrayOutputStream();
- //arguments
- int witnessSize = getWitnessComponent().size();
- //arguments的length
- Utils.writeVarint(witnessSize, witnessStream);
- for (int i = 0; i < witnessSize; i++) {
- String witness = getWitnessComponent().getWitness(i);
- Utils.writeVarStr(Hex.decode(witness), witnessStream);
- }
- byte[] dataWitnessComponents = witnessStream.toByteArray();
- //witness的length
- Utils.writeVarint(dataWitnessComponents.length, stream);
- stream.write(dataWitnessComponents);
+ ByteArrayOutputStream witnessStream = new ByteArrayOutputStream();
+ //arguments
+ int witnessSize = witnessComponent.size();
+ //arguments的length
+ Utils.writeVarint(witnessSize, witnessStream);
+ for (int i = 0; i < witnessSize; i++) {
+ String witness = witnessComponent.getWitness(i);
+ Utils.writeVarStr(Hex.decode(witness), witnessStream);
}
+ byte[] dataWitnessComponents = witnessStream.toByteArray();
+ //witness的length
+ Utils.writeVarint(dataWitnessComponents.length, stream);
+ stream.write(dataWitnessComponents);
return stream.toByteArray();
}
@Override
public void buildWitness(String txID) throws Exception {
- String rootPrvKey = getWitnessComponent().getRootPrivateKey();
+ String rootPrvKey = witnessComponent.getRootPrivateKey();
byte[] privateChild;
if (bipProtocol == BIPProtocol.BIP44) {
- privateChild = DerivePrivateKey.bip44derivePrvKey(rootPrvKey, TransactionSigner.AccountKeySpace, change, controlProgramIndex);
+ privateChild = DerivePrivateKey.bip44derivePrvKey(rootPrvKey, AccountKeySpace, change, controlProgramIndex);
} else {
- privateChild = DerivePrivateKey.bip32derivePrvKey(rootPrvKey, getKeyIndex(), TransactionSigner.AccountKeySpace, controlProgramIndex);
+ privateChild = DerivePrivateKey.bip32derivePrvKey(rootPrvKey, getKeyIndex(), AccountKeySpace, controlProgramIndex);
}
byte[] message = Utils.hashFn(Hex.decode(getInputID()), Hex.decode(txID));
byte[] expandedPrivateKey = ExpandedPrivateKey.expandedPrivateKey(privateChild);
byte[] sig = Signer.ed25519InnerSign(expandedPrivateKey, message);
- getWitnessComponent().appendWitness(Hex.toHexString(sig));
+ witnessComponent.appendWitness(Hex.toHexString(sig));
byte[] deriveXpub = DeriveXpub.deriveXpub(privateChild);
String pubKey = Hex.toHexString(deriveXpub).substring(0, 64);
- getWitnessComponent().appendWitness(pubKey);
+ witnessComponent.appendWitness(pubKey);
+ }
+
+ @Override
+ public void validate() {
+ super.validate();
+ if (sourceID == null) {
+ throw new IllegalArgumentException("the source id of spend input must be specified.");
+ }
+ if (sourcePosition == null) {
+ throw new IllegalArgumentException("the source position of spend input must be specified.");
+ }
+ if (change == null) {
+ throw new IllegalArgumentException("the change of spend input must be specified.");
+ }
+ if (controlProgramIndex == null) {
+ throw new IllegalArgumentException("the control program index of spend input must be specified.");
+ }
}
- public void setSourceId(String sourceId) {
- this.sourceId = sourceId;
+ public void setSourceID(String sourceID) {
+ this.sourceID = sourceID;
}
- public void setSourcePosition(long sourcePosition) {
+ public void setSourcePosition(int sourcePosition) {
this.sourcePosition = sourcePosition;
}
package io.bytom.api;\r
\r
import io.bytom.common.Utils;\r
+import io.bytom.exception.MapTransactionException;\r
+import io.bytom.exception.SerializeTransactionException;\r
+import io.bytom.exception.SignTransactionException;\r
import io.bytom.types.*;\r
import org.bouncycastle.util.encoders.Hex;\r
-\r
import java.io.ByteArrayOutputStream;\r
import java.io.IOException;\r
import java.util.ArrayList;\r
\r
public class Transaction {\r
\r
- public String txID;\r
+ private String txID;\r
/**\r
* version\r
*/\r
- public Integer version;\r
+ private Integer version;\r
/**\r
* size\r
*/\r
- public Integer size;\r
+ private Integer size;\r
/**\r
* time_range\r
*/\r
- public Integer timeRange;\r
+ private Integer timeRange;\r
\r
/**\r
* List of specified inputs for a transaction.\r
*/\r
- public List<BaseInput> inputs;\r
+ private List<BaseInput> inputs;\r
\r
/**\r
* List of specified outputs for a transaction.\r
*/\r
- public List<Output> outputs;\r
+ private List<Output> outputs;\r
\r
public Transaction(Builder builder) {\r
this.inputs = builder.inputs;\r
this.version = builder.version;\r
this.size = builder.size;\r
this.timeRange = builder.timeRange;\r
- mapTx();\r
- sign();\r
+\r
+ this.validate();\r
+ this.mapTransaction();\r
+ this.sign();\r
}\r
\r
public static class Builder {\r
\r
- private String txID;\r
-\r
private Integer version = 1;\r
\r
private Integer size = 0;\r
input.buildWitness(txID);\r
} catch (Exception e) {\r
e.printStackTrace();\r
- throw new RuntimeException(e);\r
+ throw new SignTransactionException(e);\r
}\r
}\r
}\r
\r
public String rawTransaction() {\r
- String rawTransaction;\r
- //开始序列化\r
ByteArrayOutputStream stream = new ByteArrayOutputStream();\r
try {\r
stream.write(7);\r
- // version\r
- if (null != version)\r
- Utils.writeVarint(version, stream);\r
- if (null != timeRange)\r
- Utils.writeVarint(timeRange, stream);\r
- //inputs\r
- if (null != inputs && inputs.size() > 0) {\r
- Utils.writeVarint(inputs.size(), stream);\r
- for (BaseInput input : inputs) {\r
- System.out.println(Hex.toHexString(input.serializeInput()));\r
- stream.write(input.serializeInput());\r
- }\r
+\r
+ Utils.writeVarint(version, stream);\r
+\r
+ Utils.writeVarint(timeRange, stream);\r
+\r
+ Utils.writeVarint(inputs.size(), stream);\r
+ for (BaseInput input : inputs) {\r
+ stream.write(input.serializeInput());\r
}\r
\r
- //outputs\r
- if (null != outputs && outputs.size() > 0) {\r
- Utils.writeVarint(outputs.size(), stream);\r
- for (Output output : outputs) {\r
- stream.write(output.serializeOutput());\r
- }\r
+ Utils.writeVarint(outputs.size(), stream);\r
+ for (Output output : outputs) {\r
+ stream.write(output.serializeOutput());\r
}\r
- byte[] data = stream.toByteArray();\r
- rawTransaction = Hex.toHexString(data);\r
} catch (IOException e) {\r
- throw new RuntimeException(e);\r
+ e.printStackTrace();\r
+ throw new SerializeTransactionException(e);\r
+ }\r
+ return Hex.toHexString(stream.toByteArray());\r
+ }\r
+\r
+ private void validate() {\r
+ if (version == null) {\r
+ throw new IllegalArgumentException("the version of transaction must be specified.");\r
+ }\r
+ if (timeRange == null) {\r
+ throw new IllegalArgumentException("the time range of transaction must be specified.");\r
+ }\r
+ if (size == null) {\r
+ throw new IllegalArgumentException("the size range of transaction must be specified.");\r
}\r
- return rawTransaction;\r
+\r
+ inputs.forEach(BaseInput::validate);\r
}\r
\r
- private void mapTx() {\r
+ private void mapTransaction() {\r
Map<Hash, Entry> entryMap = new HashMap<>();\r
ValueSource[] muxSources = new ValueSource[inputs.size()];\r
List<InputEntry> inputEntries = new ArrayList<>();\r
this.txID = txID.toString();\r
\r
} catch (Exception e) {\r
- throw new RuntimeException(e);\r
+ throw new MapTransactionException(e);\r
}\r
}\r
\r
entryMap.put(id, entry);\r
return id;\r
}\r
+\r
+ public String getTxID() {\r
+ return txID;\r
+ }\r
+\r
+ public Integer getVersion() {\r
+ return version;\r
+ }\r
+\r
+ public Integer getSize() {\r
+ return size;\r
+ }\r
+\r
+ public Integer getTimeRange() {\r
+ return timeRange;\r
+ }\r
+\r
+ public List<BaseInput> getInputs() {\r
+ return inputs;\r
+ }\r
+\r
+ public List<Output> getOutputs() {\r
+ return outputs;\r
+ }\r
}\r
+++ /dev/null
-package io.bytom.api;\r
-\r
-/**\r
- * Created by liqiang on 2018/10/24.\r
- */\r
-public class TransactionSigner {\r
-\r
- public static final byte AssetKeySpace = 0;\r
- public static final byte AccountKeySpace = 1;\r
-}\r
-\r
-\r
+++ /dev/null
-package io.bytom.api;\r
-\r
-import com.google.gson.annotations.SerializedName;\r
-import io.bytom.common.Utils;\r
-\r
-public class UTXO {\r
- /**\r
- * id : fda38648c553386c56b2f1276b908061b5d812341f0a96921abad8b2b2f28044\r
- * amount : 1700000\r
- * address : tm1qhw9q89exmudkf9ecaxtnmv22fd8af0k07jq7u5\r
- * program : 0014bb8a039726df1b649738e9973db14a4b4fd4becf\r
- * change : true\r
- * highest : 139744\r
- * account_alias : wyjbtm\r
- * asset_id : ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\r
- * asset_alias : BTM\r
- * account_id : 0NNSS39M00A02\r
- * control_program_index : 26\r
- * source_id : 34bc595dff3d40c2bd644e0ea0234e843ef8e3aa0720013a2cb712362cc5933f\r
- * source_pos : 0\r
- * valid_height : 0\r
- * derive_rule : 0\r
- */\r
-\r
- @SerializedName("id")\r
- public String id;\r
- @SerializedName("amount")\r
- public long amount;\r
- @SerializedName("address")\r
- public String address;\r
- @SerializedName("program")\r
- public String program;\r
- @SerializedName("change")\r
- public boolean change;\r
- @SerializedName("highest")\r
- public int highest;\r
- @SerializedName("account_alias")\r
- public String accountAlias;\r
- @SerializedName("asset_id")\r
- public String assetId;\r
- @SerializedName("asset_alias")\r
- public String assetAlias;\r
- @SerializedName("account_id")\r
- public String accountId;\r
- @SerializedName("control_program_index")\r
- public int controlProgramIndex;\r
- @SerializedName("source_id")\r
- public String sourceId;\r
- @SerializedName("source_pos")\r
- public int sourcePos;\r
- @SerializedName("valid_height")\r
- public int validHeight;\r
- @SerializedName("derive_rule")\r
- public int deriveRule;\r
-\r
- public String toJson() {\r
- return Utils.serializer.toJson(this);\r
- }\r
-\r
- public static UTXO fromJson(String json) {\r
- return Utils.serializer.fromJson(json, UTXO.class);\r
- }\r
-\r
- public SpendInput toSpendAnnotatedInput() {\r
- SpendInput spendInput = new SpendInput();\r
- spendInput.setAmount(amount);\r
- spendInput.setProgram(program);\r
- spendInput.setChange(change);\r
- spendInput.setAssetId(assetId);\r
- spendInput.setControlProgramIndex(controlProgramIndex);\r
- spendInput.setSourceId(sourceId);\r
- spendInput.setSourcePosition(sourcePos);\r
- return spendInput;\r
- }\r
-}\r
package io.bytom.common;\r
\r
import org.bouncycastle.util.encoders.Hex;\r
-\r
import javax.crypto.Mac;\r
import javax.crypto.spec.SecretKeySpec;\r
import java.security.InvalidKeyException;\r
import java.security.NoSuchAlgorithmException;\r
-import java.security.SignatureException;\r
\r
public class ExpandedPrivateKey {\r
- public static byte[] hmacSha512(byte[] data, byte[] key)\r
- throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {\r
+ public static byte[] hmacSha512(byte[] data, byte[] key) throws NoSuchAlgorithmException, InvalidKeyException {\r
SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA512");\r
Mac mac = Mac.getInstance("HmacSHA512");\r
mac.init(signingKey);\r
return mac.doFinal(data);\r
}\r
\r
- public static byte[] expandedPrivateKey(byte[] data)\r
- throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {\r
+ public static byte[] expandedPrivateKey(byte[] data) throws NoSuchAlgorithmException, InvalidKeyException {\r
// "457870616e64" is "Expand" hex.\r
byte[] res = hmacSha512(data, Hex.decode("457870616e64"));\r
for (int i = 0; i <= 31; i++) {\r
+++ /dev/null
-package io.bytom.common;\r
-\r
-import org.apache.log4j.Logger;\r
-import org.bouncycastle.util.encoders.Hex;\r
-\r
-public class FindDst {\r
-\r
- public static Logger logger = Logger.getLogger(FindDst.class);\r
-\r
- public static int find(String[] privateKeys, String xpub) throws Exception {\r
- // 多签情况下,找到xpub对应的private key的下标 dst\r
- int dst = -1;\r
- for (int k = 0; k < privateKeys.length; k++) {\r
- byte[] tempXpub = DeriveXpub.deriveXpub(Hex.decode(privateKeys[k]));\r
- if (xpub.equals(Hex.toHexString(tempXpub))) {\r
- dst = k;\r
- logger.info("private[dst]: " + privateKeys[dst]);\r
- break;\r
- }\r
- }\r
- if (dst == -1) {\r
- throw new Exception("Not a proper private key to sign transaction.");\r
- }\r
- return dst;\r
- }\r
-}\r
import java.io.ByteArrayOutputStream;\r
import java.security.InvalidKeyException;\r
import java.security.NoSuchAlgorithmException;\r
-import java.security.SignatureException;\r
\r
public class NonHardenedChild {\r
\r
return mac.doFinal(data);\r
}\r
\r
- public static byte[] nhChild(byte[] path, byte[] xprv, byte[] xpub) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {\r
+ public static byte[] nhChild(byte[] path, byte[] xprv, byte[] xpub) throws NoSuchAlgorithmException, InvalidKeyException {\r
// begin build data\r
ByteArrayOutputStream out = new ByteArrayOutputStream();\r
out.write('N');\r
return f;\r
}\r
\r
- public static byte[] child(byte[] xprv, String[] hpaths) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {\r
+ public static byte[] child(byte[] xprv, String[] hpaths) throws NoSuchAlgorithmException, InvalidKeyException {\r
byte[][] paths = new byte[][]{\r
Hex.decode(hpaths[0]),\r
Hex.decode(hpaths[1])\r
+++ /dev/null
-package io.bytom.common;\r
-\r
-import java.lang.reflect.ParameterizedType;\r
-import java.lang.reflect.Type;\r
-\r
-public class ParameterizedTypeImpl implements ParameterizedType {\r
-\r
- private final Class raw;\r
- private final Type[] args;\r
-\r
- public ParameterizedTypeImpl(Class raw, Type[] args) {\r
- this.raw = raw;\r
- this.args = args != null ? args : new Type[0];\r
- }\r
-\r
- @Override\r
- public Type[] getActualTypeArguments() {\r
- return args;\r
- }\r
-\r
- @Override\r
- public Type getRawType() {\r
- return raw;\r
- }\r
-\r
- @Override\r
- public Type getOwnerType() {\r
- return null;\r
- }\r
-}\r
-package io.bytom.api;\r
+package io.bytom.common;\r
\r
-import io.bytom.common.DeriveXpub;\r
-\r
-import java.security.InvalidKeyException;\r
import java.security.MessageDigest;\r
import java.security.NoSuchAlgorithmException;\r
-import java.security.SignatureException;\r
import java.util.Arrays;\r
\r
public class Signer {\r
--- /dev/null
+package io.bytom.exception;
+
+public class MapTransactionException extends RuntimeException {
+
+ public MapTransactionException() {
+ super();
+ }
+
+ public MapTransactionException(String message) {
+ super(message);
+ }
+
+ public MapTransactionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+
+ public MapTransactionException(Throwable cause) {
+ super(cause);
+ }
+}
--- /dev/null
+package io.bytom.exception;
+
+public class SerializeTransactionException extends RuntimeException {
+
+ public SerializeTransactionException() {
+ super();
+ }
+
+ public SerializeTransactionException(String message) {
+ super(message);
+ }
+
+ public SerializeTransactionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+
+ public SerializeTransactionException(Throwable cause) {
+ super(cause);
+ }
+}
--- /dev/null
+package io.bytom.exception;
+
+public class SignTransactionException extends RuntimeException {
+
+ public SignTransactionException() {
+ super();
+ }
+
+ public SignTransactionException(String message) {
+ super(message);
+ }
+
+ public SignTransactionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+
+ public SignTransactionException(Throwable cause) {
+ super(cause);
+ }
+}
public void testSpendBIP44() {\r
SpendInput input = new SpendInput(btmAssetID, 9800000000L, "0014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e");\r
input.setSourcePosition(2);\r
- input.setSourceId("4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adea");\r
+ input.setSourceID("4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adea");\r
input.setChange(true);\r
input.setControlProgramIndex(457);\r
input.setKeyIndex(1);\r
@Test\r
public void testSpendBIP32() {\r
SpendInput input = new SpendInput(btmAssetID, 11718900000L, "0014085a02ecdf934a56343aa59a3dec9d9feb86ee43");\r
- input.setSourceId("5ac79a73db78e5c9215b37cb752f0147d1157c542bb4884908ceb97abc33fe0a");\r
+ input.setSourceID("5ac79a73db78e5c9215b37cb752f0147d1157c542bb4884908ceb97abc33fe0a");\r
input.setSourcePosition(0);\r
input.setRootPrivateKey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257");\r
input.setChange(true);\r
issuanceInput.setProgram("ae2054a71277cc162eb3eb21b5bd9fe54402829a53b294deaed91692a2cd8a081f9c5151ad");\r
issuanceInput.setNonce("ac9d5a527f5ab00a");\r
issuanceInput.setKeyIndex(5);\r
- issuanceInput.setAssetDefinition("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d");\r
+ issuanceInput.setRawAssetDefinition("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d");\r
issuanceInput.setRootPrivateKey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257");\r
\r
SpendInput spendInput = new SpendInput(btmAssetID, 9800000000L, "0014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e");\r
spendInput.setBipProtocol(BIPProtocol.BIP32);\r
spendInput.setKeyIndex(1);\r
spendInput.setChange(true);\r
- spendInput.setSourceId("4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adea");\r
+ spendInput.setSourceID("4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adea");\r
spendInput.setSourcePosition(2);\r
spendInput.setControlProgramIndex(457);\r
spendInput.setRootPrivateKey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257");\r
String retireControlProgram = "6a"+Integer.toString(Hex.decode(arbitrary).length,16)+arbitrary;\r
String assetId1 = "207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf";\r
\r
- SpendInput input1 = new SpendInput(btmAssetID, 289100000, "0014f1dc52048f439ac7fd74f8106a21da78f00de48f");\r
+ SpendInput input1 = new SpendInput(btmAssetID, 289100000L, "0014f1dc52048f439ac7fd74f8106a21da78f00de48f");\r
input1.setRootPrivateKey(rootKey);\r
input1.setChange(true);\r
input1.setControlProgramIndex(41);\r
- input1.setSourceId("0b2cff11d1d056d95237a5f2d06059e5395e86f60e69c1e8201ea624911c0c65");\r
+ input1.setSourceID("0b2cff11d1d056d95237a5f2d06059e5395e86f60e69c1e8201ea624911c0c65");\r
input1.setSourcePosition(0);\r
\r
SpendInput input2 = new SpendInput(assetId1, 70000000000L, "0014bb8a039726df1b649738e9973db14a4b4fd4becf");\r
input2.setRootPrivateKey(rootKey);\r
input2.setChange(true);\r
input2.setControlProgramIndex(26);\r
- input2.setSourceId("be0ac837e832c34a02968e54dab4f95cbeceb9fb01cd378310f6ea32219ee29b");\r
+ input2.setSourceID("be0ac837e832c34a02968e54dab4f95cbeceb9fb01cd378310f6ea32219ee29b");\r
input2.setSourcePosition(1);\r
\r
- Output output1 = new Output(btmAssetID, 279100000, "001414d362694eacfa110dc20dec77d610d22340f95b");\r
+ Output output1 = new Output(btmAssetID, 279100000L, "001414d362694eacfa110dc20dec77d610d22340f95b");\r
Output output2 = new Output(assetId1, 10000000000L, retireControlProgram);\r
Output output3 = new Output(assetId1, 60000000000L, "0014bb8a039726df1b649738e9973db14a4b4fd4becf");\r
\r
String rawTransaction = transaction.rawTransaction();\r
assert rawTransaction.equals("070180897a020160015e0b2cff11d1d056d95237a5f2d06059e5395e86f60e69c1e8201ea624911c0c65ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0a1ed89010001160014f1dc52048f439ac7fd74f8106a21da78f00de48f6302401660121218ab96d9f22cce712541ca34c53f4da40450669854341ca9624ad1cf10d1bfc96449fad5406224afd253ccfbdeab683f7ec7f9ee8f45e47a0c58500f2031ecc1bdd5fb9b40016358340b87646ea39faf55c0c105205cfdfdc6184725f40161015fbe0ac837e832c34a02968e54dab4f95cbeceb9fb01cd378310f6ea32219ee29b207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf80f8cce284020101160014bb8a039726df1b649738e9973db14a4b4fd4becf630240d7b7f1c2ca1048fd6798234f2a1e895762f83e802507a008eff52605611b67390a74eaf228b76f5589ff109b2c20eaa65fad6de2e5ab8a25b54267b607df970b20a71547e1064b5edaad92cdce6b0ace832836ba28fdeaf0b83010bed247fe927c03013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f48a85010116001414d362694eacfa110dc20dec77d610d22340f95b00014b207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf80c8afa02501246a2277656c636f6d65efbc8ce6aca2e8bf8ee69da5e588b0e58e9fe5ad90e4b896e7958c00013e207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf80b09dc2df0101160014bb8a039726df1b649738e9973db14a4b4fd4becf00");\r
}\r
-\r
-\r
- //utxo\r
- private SpendInput btmUtxoToInput() {\r
- String utxoJson = "\n" +\r
- "{\n" +\r
- " \"id\": \"687e3c3ca1ee8139e57f43697db6aaeac95b10c75b828ef2fad30abe7d047e6a\",\n" +\r
- " \"amount\": 10000000,\n" +\r
- " \"address\": \"tm1qznfky62w4napzrwzphk804ss6g35p72mcw53q7\",\n" +\r
- " \"program\": \"001414d362694eacfa110dc20dec77d610d22340f95b\",\n" +\r
- " \"change\": false,\n" +\r
- " \"highest\": 141905,\n" +\r
- " \"account_alias\": \"wyjbtm\",\n" +\r
- " \"asset_id\": \"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\",\n" +\r
- " \"asset_alias\": \"BTM\",\n" +\r
- " \"account_id\": \"0NNSS39M00A02\",\n" +\r
- " \"control_program_index\": 2,\n" +\r
- " \"source_id\": \"535b88d3f6b449fdba678b00b84d4b516df1da73104d689d41f964389f5a9217\",\n" +\r
- " \"source_pos\": 1,\n" +\r
- " \"valid_height\": 0,\n" +\r
- " \"derive_rule\": 0\n" +\r
- "}";\r
- UTXO utxo = UTXO.fromJson(utxoJson);\r
- return utxo.toSpendAnnotatedInput();\r
- }\r
}\r
package io.bytom.api;\r
\r
+import io.bytom.common.Signer;\r
import org.bouncycastle.util.encoders.Hex;\r
import org.junit.Test;\r
\r
+++ /dev/null
-package io.bytom.api;\r
-\r
-import org.junit.Test;\r
-\r
-import java.security.InvalidKeyException;\r
-import java.security.NoSuchAlgorithmException;\r
-import java.security.SignatureException;\r
-\r
-public class UTXOTest {\r
- @Test\r
- public void testJson() throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {\r
- String json = "{\n" +\r
- " \"id\": \"fda38648c553386c56b2f1276b908061b5d812341f0a96921abad8b2b2f28044\",\n" +\r
- " \"amount\": 1700000,\n" +\r
- " \"address\": \"tm1qhw9q89exmudkf9ecaxtnmv22fd8af0k07jq7u5\",\n" +\r
- " \"program\": \"0014bb8a039726df1b649738e9973db14a4b4fd4becf\",\n" +\r
- " \"change\": true,\n" +\r
- " \"highest\": 139744,\n" +\r
- " \"account_alias\": \"wyjbtm\",\n" +\r
- " \"asset_id\": \"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\",\n" +\r
- " \"asset_alias\": \"BTM\",\n" +\r
- " \"account_id\": \"0NNSS39M00A02\",\n" +\r
- " \"control_program_index\": 26,\n" +\r
- " \"source_id\": \"34bc595dff3d40c2bd644e0ea0234e843ef8e3aa0720013a2cb712362cc5933f\",\n" +\r
- " \"source_pos\": 0,\n" +\r
- " \"valid_height\": 0,\n" +\r
- " \"derive_rule\": 0\n" +\r
- "}";\r
-\r
- UTXO utxo = UTXO.fromJson(json);\r
- System.out.println(utxo.toJson());\r
- }\r
-\r
-\r
-}\r