org.coinspark.protocol.CoinSparkGenesis Maven / Gradle / Ivy
/*
* CoinSpark 2.1 - Java library
*
* Copyright (c) Coin Sciences Ltd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.coinspark.protocol;
import java.util.Arrays;
/**
* CoinSparkGenesis class for managing asset genesis metadata
*/
public class CoinSparkGenesis extends CoinSparkBase{
public static final int COINSPARK_GENESIS_DOMAIN_NAME_MAX_LEN = 32;
public static final int COINSPARK_GENESIS_PAGE_PATH_MAX_LEN = 24;
// Public functions
/**
* CoinSparkGenesis class for managing asset genesis metadata
*/
public CoinSparkGenesis()
{
clear();
}
/**
* Set all fields in genesis to their default/zero values, which are not necessarily valid.
*/
public final void clear()
{
qtyExponent = 0;
qtyMantissa = 0;
chargeFlatMantissa = 0;
chargeFlatExponent = 0;
chargeBasisPoints = 0; // one hundredths of a percent
assetHash = new byte[COINSPARK_GENESIS_HASH_MAX_LEN];
assetHashLen = 0; // number of bytes in assetHash that are valid for comparison
domainName="";
pagePath="";
useHttps=false;
usePrefix=true;
}
/**
* Returns Charge basis points
*
* @return Charge basis points
*/
public short getChargeBasisPoints() {
return chargeBasisPoints;
}
/**
* sets Charge basis points
*
* @param ChargeBasisPoints to set
*/
public void setChargeBasisPoints(short ChargeBasisPoints) {
chargeBasisPoints = ChargeBasisPoints;
}
/**
* Returns Charge flat mantissa
*
* @return Charge flat mantissa
*/
public short getChargeFlatMantissa() {
return chargeFlatMantissa;
}
/**
* Sets Charge flat mantissa.
*
* @param ChargeFlatMantissa to set
*/
public void setChargeFlatMantissa(short ChargeFlatMantissa) {
chargeFlatMantissa = ChargeFlatMantissa;
}
/**
* Returns Charge flat exponent
*
* @return Charge flat exponent
*/
public short getChargeFlatExponent() {
return chargeFlatExponent;
}
/**
* Sets Charge flat exponent
*
* @param ChargeFlatExponent to set
*/
public void setChargeFlatExponent(short ChargeFlatExponent) {
chargeFlatExponent = ChargeFlatExponent;
}
/**
* Returns Quantity exponent
*
* @return Quantity exponent
*/
public short getQtyExponent() {
return qtyExponent;
}
/**
* Sets Quantity exponent
*
* @param QtyExponent to set
*/
public void setQtyExponent(short QtyExponent) {
qtyExponent = QtyExponent;
}
/**
* Returns Quantity mantissa
*
* @return Quantity mantissa
*/
public short getQtyMantissa() {
return qtyMantissa;
}
/**
* Sets Quantity mantissa
*
* @param QtyMantissa to set
*/
public void setQtyMantissa(short QtyMantissa) {
qtyMantissa = QtyMantissa;
}
/**
* Returns Domain Name
*
* @return Domain Name
*/
public String getDomainName() {
return domainName;
}
/**
* Sets DomainName
*
* @param DomainName to set
*/
public void setDomainName(String DomainName) {
domainName = DomainName;
}
/**
* Returns Page Path
*
* @return Page Path
*/
public String getPagePath() {
return pagePath;
}
/**
* Sets Page Path
*
* @param PagePath to set
*/
public void setPagePath(String PagePath) {
pagePath = PagePath;
}
/**
* Returns Use https flag
*
* @return Use https flag
*/
public boolean getUseHttps() {
return useHttps;
}
/**
* Sets Use https flag
*
* @param UseHttps to set
*/
public void setUseHttps(boolean UseHttps) {
useHttps = UseHttps;
}
/**
* Returns Use path prefix flag
*
* @return Use path prefix flag
*/
public boolean getUsePrefix() {
return usePrefix;
}
/**
* Sets Use path prefix flag
*
* @param UsePrefix flag to set
*/
public void setUsePrefix(boolean UsePrefix) {
usePrefix = UsePrefix;
}
/**
* Returns Asset hash
*
* @return Asset hash
*/
public byte [] getAssetHash() {
return assetHash;
}
/**
* Returns Asset hash length (to be) encoded
*
* @return Asset hash length
*/
public int getAssetHashLen() {
return assetHashLen;
}
/**
* Sets asset hash.
*
* @param AssetHash to set
*/
public void setAssetHash(byte [] AssetHash) {
assetHash=Arrays.copyOf(AssetHash, AssetHash.length);
}
/**
* Sets asset hash.
*
* @param AssetHashLen to set
*/
public void setAssetHashLen(int AssetHashLen) {
assetHashLen=AssetHashLen;
}
@Override
public String toString()
{
long quantity = getQty();
int quantityEncoded = (this.qtyExponent * COINSPARK_GENESIS_QTY_EXPONENT_MULTIPLE + this.qtyMantissa) &
COINSPARK_GENESIS_QTY_MASK;
long chargeFlat = getChargeFlat();
int chargeFlatEncoded = this.chargeFlatExponent*COINSPARK_GENESIS_CHARGE_FLAT_EXPONENT_MULTIPLE + this.chargeFlatMantissa;
StringBuilder sb = new StringBuilder();
CoinSparkBuffer assetWebPageBuffer=new CoinSparkBuffer();
String encodedWebPage="";
CoinSparkDomainPath assetWebPage=new CoinSparkDomainPath(domainName, pagePath, useHttps, usePrefix);
if(assetWebPage.encode(assetWebPageBuffer,false))
{
encodedWebPage=assetWebPageBuffer.toHex();
}
sb.append("COINSPARK GENESIS\n")
.append(String.format(" Quantity mantissa: %d\n", this.qtyMantissa))
.append(String.format(" Quantity exponent: %d\n", this.qtyExponent))
.append(String.format(" Quantity encoded: %d (small endian hex %s)\n", quantityEncoded,
unsignedToSmallEndianHex(quantityEncoded, 2)))
.append(String.format(" Quantity value: %d\n", quantity))
.append(String.format("Flat charge mantissa: %d\n", this.chargeFlatMantissa))
.append(String.format("Flat charge exponent: %d\n", this.chargeFlatExponent))
.append(String.format(" Flat charge encoded: %d (small endian hex %s)\n", chargeFlatEncoded,
unsignedToSmallEndianHex(chargeFlatEncoded, COINSPARK_GENESIS_CHARGE_FLAT_LENGTH)))
.append(String.format(" Flat charge value: %d\n", chargeFlat))
.append(String.format(" Basis points charge: %d (hex %s)\n", this.chargeBasisPoints,
unsignedToSmallEndianHex(this.chargeBasisPoints, COINSPARK_GENESIS_CHARGE_BPS_LENGTH)))
.append(String.format(" Asset URL: %s://%s/%s%s/ (length %d+%d encoded %s length %d)\n",
assetWebPage.useHttps ? "https" : "http", assetWebPage.domainName,
assetWebPage.usePrefix ? "coinspark/" : "",
(assetWebPage.path.length()>0) ? assetWebPage.path : "[spent-txid]",
assetWebPage.domainName.length(),assetWebPage.path.length(),
encodedWebPage,assetWebPage.encodedLen(false)))
.append(String.format(" Asset hash: "))
.append(byteToHex(Arrays.copyOf(assetHash, assetHashLen)))
.append(String.format(" (length %d)\n", this.assetHashLen))
.append(String.format("END COINSPARK GENESIS\n\n"));
return sb.toString();
}
/**
* Returns true if the two CoinSparkGenesis structures are the same. If strict is true then
* the qtyMantissa, qtyExponent, chargeFlatMantissa and chargeFlatExponent fields must be identical.
* If strict is false then it is enough if each pair just represents the same final quantity.
*
* @param genesis2 CoinSparkGenesis to compare with
* @param strict Strict comparison flag
* @return true if two CoinSparkGenesis match, false otherwise
*/
public boolean match(CoinSparkGenesis genesis2, boolean strict)
{
boolean floatQuantitiesMatch;
int hashCompareLen = Math.min(this.assetHashLen, genesis2.assetHashLen);
hashCompareLen = Math.min(hashCompareLen, COINSPARK_GENESIS_HASH_MAX_LEN);
CoinSparkDomainPath assetWebPage=new CoinSparkDomainPath(domainName, pagePath, useHttps, usePrefix);
CoinSparkDomainPath assetWebPage2=new CoinSparkDomainPath(genesis2.getDomainName(),
genesis2.getPagePath(), genesis2.getUseHttps(), genesis2.getUsePrefix());
if (strict)
floatQuantitiesMatch=(this.qtyMantissa == genesis2.qtyMantissa) &&
(this.qtyExponent == genesis2.qtyExponent) &&
(this.chargeFlatMantissa == genesis2.chargeFlatMantissa) &&
(this.chargeFlatExponent == genesis2.chargeFlatExponent);
else
floatQuantitiesMatch=(this.getQty() == genesis2.getQty()) &&
(this.getChargeFlat()==genesis2.getChargeFlat());
return
floatQuantitiesMatch && (this.chargeBasisPoints == genesis2.chargeBasisPoints) &&
assetWebPage.match(assetWebPage2) &&
(memcmp(this.assetHash, genesis2.assetHash, hashCompareLen) == 0)
;
}
/**
* Returns true if all values in the genesis are in their permitted ranges, false otherwise.
*
* @return true if genesis structure is valid
*/
public boolean isValid()
{
if ( (qtyMantissaCOINSPARK_GENESIS_QTY_MANTISSA_MAX) )
return false;
if ( (qtyExponentCOINSPARK_GENESIS_QTY_EXPONENT_MAX) )
return false;
if ( (chargeFlatExponentCOINSPARK_GENESIS_CHARGE_FLAT_EXPONENT_MAX) )
return false;
if (chargeFlatMantissa ((chargeFlatExponent==COINSPARK_GENESIS_CHARGE_FLAT_EXPONENT_MAX) ?
COINSPARK_GENESIS_CHARGE_FLAT_MANTISSA_MAX_IF_EXP_MAX : COINSPARK_GENESIS_CHARGE_FLAT_MANTISSA_MAX))
return false;
if ( (chargeBasisPointsCOINSPARK_GENESIS_CHARGE_BASIS_POINTS_MAX) )
return false;
CoinSparkDomainPath assetWebPage=new CoinSparkDomainPath(domainName, pagePath, useHttps, usePrefix);
if (!assetWebPage.isValid())
return false;
if ( (assetHashLenCOINSPARK_GENESIS_HASH_MAX_LEN) )
return false;
return true;
}
/**
* Returns the number of units denoted by the genesis qtyMantissa and qtyExponent fields.
*
* @return the number of units denoted by the genesis qtyMantissa and qtyExponent fields.
*/
public long getQty()
{
return new CoinSparkAssetQty(this.qtyMantissa, this.qtyExponent).value;
}
/**
* Sets the qtyMantissa and qtyExponent fields in genesis to be as close to desiredQty as possible.
* Set rounding to [-1, 0, 1] for rounding [down, closest, up] respectively.
* Returns the quantity that was actually encoded, via CoinSparkGenesisGetQty().
*
* @param desiredQty desired quantity
* @param rounding [-1, 0, 1] for rounding [down, closest, up] respectively.
* @return the quantity that was actually encoded
*/
public long setQty(long desiredQty, int rounding)
{
CoinSparkAssetQty qty=new CoinSparkAssetQty(desiredQty, rounding,
COINSPARK_GENESIS_QTY_MANTISSA_MAX, COINSPARK_GENESIS_QTY_EXPONENT_MAX);
qtyMantissa = (short)qty.mantissa;
qtyExponent = (short)qty.exponent;
return getQty();
}
/**
* Returns the number of units denoted by the genesis chargeFlatMantissa and chargeFlatExponent fields.
*
* @return the number of units denoted by the genesis chargeFlatMantissa and chargeFlatExponent fields.
*/
public long getChargeFlat()
{
return new CoinSparkAssetQty(this.chargeFlatMantissa, this.chargeFlatExponent).value;
}
/**
* Sets the chargeFlatMantissa and chargeFlatExponent fields in genesis to be as close to desiredChargeFlat as possible.
* Set rounding to [-1, 0, 1] for rounding [down, closest, up] respectively.
* Returns the quantity that was actually encoded, via CoinSparkGenesisGetChargeFlat().
*
* @param desiredChargeFlat desired quantity
* @param rounding [-1, 0, 1] for rounding [down, closest, up] respectively.
* @return the quantity that was actually encoded
*/
public long setChargeFlat(long desiredChargeFlat, int rounding)
{
CoinSparkAssetQty qty=new CoinSparkAssetQty(desiredChargeFlat, rounding,
COINSPARK_GENESIS_CHARGE_FLAT_MANTISSA_MAX, COINSPARK_GENESIS_CHARGE_FLAT_EXPONENT_MAX);
chargeFlatMantissa = (short)qty.mantissa;
chargeFlatExponent = (short)qty.exponent;
if (chargeFlatExponent == COINSPARK_GENESIS_CHARGE_FLAT_EXPONENT_MAX)
chargeFlatMantissa = (short)Math.min(chargeFlatMantissa, COINSPARK_GENESIS_CHARGE_FLAT_MANTISSA_MAX_IF_EXP_MAX);
return getChargeFlat();
}
/**
* Calculates the payment charge specified by genesis for sending the raw quantity qtyGross.
*
* @param qtyGross quantity to send
* @return the payment charge
*/
public long calcCharge(long qtyGross)
{
long charge = getChargeFlat() +(qtyGross*this.chargeBasisPoints+5000)/10000; // rounds to nearest
if (charge > qtyGross)// can't charge more than the final amount
charge = qtyGross;
return charge;
}
/**
* Calculates the quantity that will be received after the payment charge specified by genesis is applied to qtyGross.
*
* @param qtyGross quantity to send
* @return the quantity that will be received
*/
public long calcNet(long qtyGross)
{
return qtyGross - calcCharge(qtyGross);
}
/**
* Calculates the quantity that should be sent so that, after the payment charge specified by genesis
* is applied, the recipient will receive qtyNet units.
*
* @param qtyNet quantity to receive
* @return the quantity that should be sent
*/
public long calcGross(long qtyNet)
{
if (qtyNet <=0)
return 0; // no point getting past charges if we end up with zero anyway
long lowerGross = ((qtyNet + getChargeFlat()) * 10000)/
(10000-chargeBasisPoints); // divides rounding down
if (calcNet(lowerGross) < qtyNet)
lowerGross+=1;
return lowerGross;
}
/**
* Calculates the appropriate asset hash length of genesis so that when encoded as metadata the genesis will
* fit in metadataMaxLen bytes. For now, set metadataMaxLen to 40 (see Bitcoin's MAX_OP_RETURN_RELAY parameter).
*
* @param metadataMaxLen - metadata maximal length
* @return asset hash length of genesis
*/
public int calcHashLen(int metadataMaxLen)
{
int HashLen = metadataMaxLen-COINSPARK_METADATA_IDENTIFIER.length()-1-COINSPARK_GENESIS_QTY_FLAGS_LENGTH;
if (this.chargeFlatMantissa>0)
HashLen-=COINSPARK_GENESIS_CHARGE_FLAT_LENGTH;
if (this.chargeBasisPoints>0)
HashLen-=COINSPARK_GENESIS_CHARGE_BPS_LENGTH;
CoinSparkDomainPath assetWebPage=new CoinSparkDomainPath(domainName, pagePath, useHttps, usePrefix);
HashLen-=assetWebPage.encodedLen(false);
if (HashLen > COINSPARK_GENESIS_HASH_MAX_LEN)
HashLen = COINSPARK_GENESIS_HASH_MAX_LEN;
return HashLen;
}
/**
* Encodes the genesis into metadata (maximal size is CoinSparkBase.OP_RETURN_MAXIMUM_LENGTH);
*
* @return String | null Encoded genesis as hexadecimal, null if we failed.
*/
/*
public String encodeToHex()
{
return encodeToHex(OP_RETURN_MAXIMUM_LENGTH);
}
*/
/**
* Encodes the genesis into metadata (maximal size is metadataMaxLen);
*
* @param metadataMaxLen maximal size of encoded data
* @return String | null Encoded genesis as hexadecimal, null if we failed.
*/
public String encodeToHex(int metadataMaxLen)
{
CoinSparkBuffer buffer=new CoinSparkBuffer();
if(!encode(buffer,metadataMaxLen))
{
return null;
}
return buffer.toHex();
}
/**
* Encodes the genesis into metadata (maximal size is CoinSparkBase.OP_RETURN_MAXIMUM_LENGTH);
*
* @return byte [] | null Encoded genesis as raw data, null if we failed.
*/
/*
public byte [] encode()
{
return encode(OP_RETURN_MAXIMUM_LENGTH);
}
*/
/**
* Encodes the genesis into metadata (maximal size is metadataMaxLen);
*
* @param metadataMaxLen maximal size of encoded data
* @return byte [] | null Encoded genesis as hexadecimal, null if we failed.
*/
public byte [] encode(int metadataMaxLen)
{
CoinSparkBuffer buffer=new CoinSparkBuffer();
if(!encode(buffer,metadataMaxLen))
{
return null;
}
return buffer.toBytes();
}
/**
* Decodes the genesis in metadata into paymentRef.
*
* @param metadata Metadata to decode as hexadecimal
* @return true on success, false on failure
*/
public boolean decode(String metadata)
{
CoinSparkBuffer buffer=new CoinSparkBuffer(metadata, true);
return decode(buffer);
}
/**
* Decodes the genesis in metadata into paymentRef.
*
* @param metadata Metadata to decode as raw data
* @return true on success, false on failure
*/
public boolean decode(byte [] metadata)
{
CoinSparkBuffer buffer=new CoinSparkBuffer(metadata);
return decode(buffer);
}
/**
* Returns the minimum transaction fee (in bitcoin satoshis) required to make the genesis transaction valid.
* Pass the number of bitcoin satoshis in each output in outputsSatoshis (array size countOutputs).
* Use CoinSparkScriptIsRegular() to pass an array of bools in outputsRegular for whether each output script is regular.
*
* @param outputsSatoshis array of output values
* @param outputsRegular pass array of booleans for whether each output script is regular
* @return minimum transaction fee
*/
public long calcMinFee(long[] outputsSatoshis, boolean[] outputsRegular)
{
return getMinFeeBasis(outputsSatoshis, outputsRegular) *
countNonLastRegularOutputs(outputsRegular);
}
/**
* For the asset specified by genesis, calculate the number of newly created asset units in each
* output of the genesis transaction into the outputBalances array (size countOutputs).
* Use CoinSparkScriptIsRegular() to pass an array of bools in outputsRegular for whether each output script is regular.
* ** This is only relevant if the transaction DOES HAVE a sufficient fee to make the genesis valid **
*
* @param outputsRegular array of bools in outputsRegular for whether each output script is regular
* @return output balances
*/
public long [] apply(boolean[] outputsRegular)
{
int countOutputs=outputsRegular.length;
long [] outputBalances=new long [countOutputs];
long qtyPerOutput;
int lastRegularOutput = getLastRegularOutput(outputsRegular);
int divideOutputs = countNonLastRegularOutputs(outputsRegular);
long genesisQty = getQty();
if (divideOutputs==0)
qtyPerOutput = 0;
else
qtyPerOutput = genesisQty / (divideOutputs); // rounds down
long extraFirstOutput = genesisQty - (qtyPerOutput * divideOutputs);
for (int outputIndex=0; outputIndex0)
quantityEncoded|=COINSPARK_GENESIS_FLAG_CHARGE_FLAT;
if (chargeBasisPoints>0)
quantityEncoded|=COINSPARK_GENESIS_FLAG_CHARGE_BPS;
buffer.writeInt(quantityEncoded, COINSPARK_GENESIS_QTY_FLAGS_LENGTH);
// Charges - flat and basis points
if ((quantityEncoded & COINSPARK_GENESIS_FLAG_CHARGE_FLAT) != 0)
{
int chargeEncoded=this.chargeFlatExponent*COINSPARK_GENESIS_CHARGE_FLAT_EXPONENT_MULTIPLE+this.chargeFlatMantissa;
buffer.writeInt(chargeEncoded, COINSPARK_GENESIS_CHARGE_FLAT_LENGTH);
}
if ((quantityEncoded & COINSPARK_GENESIS_FLAG_CHARGE_BPS) != 0)
{
buffer.writeInt(chargeBasisPoints, COINSPARK_GENESIS_CHARGE_BPS_LENGTH);
}
// Asset web page
CoinSparkDomainPath assetWebPage=new CoinSparkDomainPath(domainName, pagePath, useHttps, usePrefix);
if (!assetWebPage.encode(buffer,false))
throw new CoinSparkExceptions.CannotEncode("cannot write domain name/path");
// Asset hash
buffer.writeBytes(assetHash, assetHashLen);
if(buffer.length()>metadataMaxLen)
throw new CoinSparkExceptions.CannotEncode("total length above limit");
}
catch (Exception ex)
{
System.out.print(ex.getMessage());
return false;
}
return true;
}
private boolean decode(CoinSparkBuffer buffer)
{
int quantityEncoded, chargeEncoded;
if(!buffer.locateRange(COINSPARK_GENESIS_PREFIX))
return false;
try
{
// Quantity mantissa and exponent
if(buffer.canRead(COINSPARK_GENESIS_QTY_FLAGS_LENGTH))
{
quantityEncoded = buffer.readInt(COINSPARK_GENESIS_QTY_FLAGS_LENGTH);
qtyMantissa = (short)((quantityEncoded&COINSPARK_GENESIS_QTY_MASK) % COINSPARK_GENESIS_QTY_EXPONENT_MULTIPLE);
qtyExponent = (short)((quantityEncoded&COINSPARK_GENESIS_QTY_MASK) / COINSPARK_GENESIS_QTY_EXPONENT_MULTIPLE);
if ((qtyMantissa < COINSPARK_GENESIS_QTY_MANTISSA_MIN) ||
(qtyMantissa > COINSPARK_GENESIS_QTY_MANTISSA_MAX) )
throw new CoinSparkExceptions.CannotDecode("mantissa out of range");
if ((qtyExponent < COINSPARK_GENESIS_QTY_EXPONENT_MIN) ||
(qtyExponent > COINSPARK_GENESIS_QTY_EXPONENT_MAX) )
throw new CoinSparkExceptions.CannotDecode("exponent out of range");
}
else
throw new CoinSparkExceptions.CannotDecode("cannot read genesis flags");
// Charges - flat and basis points
if ((quantityEncoded & COINSPARK_GENESIS_FLAG_CHARGE_FLAT) !=0)
{
if(buffer.canRead(COINSPARK_GENESIS_CHARGE_FLAT_LENGTH))
{
chargeEncoded = buffer.readInt(COINSPARK_GENESIS_CHARGE_FLAT_LENGTH);
this.chargeFlatMantissa = (short)(chargeEncoded % COINSPARK_GENESIS_CHARGE_FLAT_EXPONENT_MULTIPLE);
this.chargeFlatExponent = (short)(chargeEncoded / COINSPARK_GENESIS_CHARGE_FLAT_EXPONENT_MULTIPLE);
if ( (this.chargeFlatExponentCOINSPARK_GENESIS_CHARGE_FLAT_EXPONENT_MAX) )
throw new CoinSparkExceptions.CannotDecode("flat exponent out of range");
if (this.chargeFlatMantissa (
(this.chargeFlatExponent==COINSPARK_GENESIS_CHARGE_FLAT_EXPONENT_MAX) ?
COINSPARK_GENESIS_CHARGE_FLAT_MANTISSA_MAX_IF_EXP_MAX : COINSPARK_GENESIS_CHARGE_FLAT_MANTISSA_MAX))
throw new CoinSparkExceptions.CannotDecode("flat mantissa out of range");
}
else
throw new CoinSparkExceptions.CannotDecode("cannot read charge flat");
}
else
{
this.chargeFlatMantissa=0;
this.chargeFlatExponent=0;
}
if ((quantityEncoded & COINSPARK_GENESIS_FLAG_CHARGE_BPS) != 0)
{
if(buffer.canRead(COINSPARK_GENESIS_CHARGE_BPS_LENGTH))
{
this.chargeBasisPoints = buffer.readInt(COINSPARK_GENESIS_CHARGE_BPS_LENGTH).shortValue();
if ( (this.chargeBasisPointsCOINSPARK_GENESIS_CHARGE_BASIS_POINTS_MAX) )
throw new CoinSparkExceptions.CannotDecode("basic points out of range");
}
else
throw new CoinSparkExceptions.CannotDecode("cannot read basic points");
} else
this.chargeBasisPoints=0;
// Domain name
CoinSparkDomainPath assetWebPage=new CoinSparkDomainPath(domainName, pagePath, useHttps, usePrefix);
if (!assetWebPage.decode(buffer,false))
throw new CoinSparkExceptions.CannotDecode("cannot decode domain name");
domainName=assetWebPage.domainName;
pagePath=assetWebPage.path;
useHttps=assetWebPage.useHttps;
usePrefix=assetWebPage.usePrefix;
// Hash of key information
assetHashLen = buffer.availableForRead();//TBD loss
assetHashLen = Math.min(assetHashLen, COINSPARK_GENESIS_HASH_MAX_LEN); // apply maximum
if (assetHashLen < COINSPARK_GENESIS_HASH_MIN_LEN)
// not enough hash data
throw new CoinSparkExceptions.CannotDecode("has data out of range");
assetHash=buffer.readBytes(assetHashLen);
}
catch (Exception ex)
{
System.out.print(ex.getMessage());
return false;
}
return isValid();
}
private static int countNonLastRegularOutputs(boolean[] outputsRegular)
{
int countRegularOutputs, outputIndex;
int countOutputs=outputsRegular.length;
countRegularOutputs=0;
for (outputIndex=0; outputIndex 1 ? countRegularOutputs-1 : 0;
}
private static String trimForHash(String Source)
{
if(Source == null)
{
return null;
}
boolean keepTrimming;
int from = 0;
int to = Source.length()-1;
keepTrimming = true;
while(keepTrimming && (from=0))
{
switch (Source.charAt(to))
{
case 0x09: case 0x0A: case 0x0D: case 0x20:
to--;
break;
default:
keepTrimming = false;
break;
}
}
to++;
if(from>=to)
{
return null;
}
return Source.substring(from,to);
}
private static int addToHashBuffer(String string, byte[] buffer, int offset)
{
String trimmed=trimForHash(string);
if (trimmed != null && trimmed.length() !=0)
{
System.arraycopy(trimmed.getBytes(), 0, buffer, offset, trimmed.length());
buffer[offset+trimmed.length()] = 0x00;
return trimmed.length()+1;
}
else
{
buffer[offset]=0x00;
return 1;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy