Minimum transaction fees protect the CoinSpark system from denial-of-service attacks.

If a bitcoin transaction has CoinSpark genesis or transfer metadata attached, that metadata is only considered valid if the transaction has a sufficient transaction fee, which is collected by the miner who included that transaction in a bitcoin block. There is no minimum fee required for payment reference metadata to be valid.

Without minimum fees, CoinSpark would be vulnerable to an attack in which a user could create a large number of unspent bitcoin transaction outputs each of which contains a large number of different assets. This would not cause a problem for services such as asset tracking servers following the movements of an individual asset type over bitcoin transactions. However it would greatly inflate the storage requirements of any service attempting to track the movements of all CoinSpark assets.

CoinSpark’s minimum fee is calculated from the number of new asset outputs that a transaction might create multiplied by the lower of: (a) the quantity of bitcoin in the smallest non-OP_RETURN output of that transaction, and (b) 1000 satoshis. In this way, CoinSpark piggybacks on the anti-dust threshold introduced in Bitcoin 0.8.2, without being tied to a particular value of that threshold. If new versions of Bitcoin Core reduce this threshold (currently ~550 satoshis in Bitcoin 0.9), and so allow transactions with smaller outputs to be relayed by the default bitcoin client, CoinSpark’s minimum fees for new transactions can drop in tandem. If new versions of Bitcoin Core greatly increase this threshold, CoinSpark will still treat 1000 satoshis as an upper limit. In either case, the valid or invalid status of CoinSpark metadata on an old transaction is determined entirely by that transaction, independent of the current anti-dust threshold.

You can easily calculate the minimum transaction fee required for CoinSpark metadata to be valid using the appropriate CoinSpark library for your programming language.

Checking if genesis metadata has a sufficient fee

C/C++

bool CheckGenesisFee(const CoinSparkGenesis *genesis, const CoinSparkSatoshiQty feeSatoshis,
    const CoinSparkSatoshiQty* outputsSatoshis, const char* scriptPubKeys[],
    const size_t scriptPubKeysLen[], const bool scriptsAreHex, const int countOutputs)
{
    // genesis points to a CoinSparkGenesis structure, already extracted from the transaction.
    // feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
    // outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
    // scriptPubKeys is an array of pointers to each output script of the transaction.
    // Depending on scriptsAreHex, scriptPubKeys contains hex strings or raw binary data.
    // scriptPubKeysLen is an array of byte lengths for each element of scriptPubKeys.

    bool *outputsRegular;
    int output;
    CoinSparkSatoshiQty minFeeSatoshis;

    outputsRegular=(bool*)malloc(countOutputs*sizeof(bool));

    for (output=0; output<countOutputs; output++)
        outputsRegular[output]=CoinSparkScriptIsRegular(scriptPubKeys[output],
            scriptPubKeysLen[output], scriptsAreHex);

    minFeeSatoshis=CoinSparkGenesisCalcMinFee(genesis, outputsSatoshis, outputsRegular, countOutputs);

    free(outputsRegular);

    return feeSatoshis>=minFeeSatoshis;
}

Java

// public static boolean CheckGenesisFee(CoinSparkGenesis genesis, long feeSatoshis,
//     long[] outputsSatoshis, byte[][] scriptPubKeys)

public static boolean CheckGenesisFee(CoinSparkGenesis genesis, long feeSatoshis,
    long[] outputsSatoshis, String[] scriptPubKeys)
{
    // genesis is a CoinSparkGenesis object, already extracted from the transaction.
    // feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
    // outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
    // scriptPubKeys is an array containing each output script of a transaction as a hex string
    // or raw binary (commented above), so that the transaction has scriptPubKeys.length outputs.

    int countOutputs=scriptPubKeys.length;
    boolean[] outputsRegular=new boolean[countOutputs];

    for (int output=0; output<countOutputs; output++)
        outputsRegular[output]=CoinSparkBase.scriptIsRegular(scriptPubKeys[output]);

    return feeSatoshis>=genesis.calcMinFee(outputsSatoshis, outputsRegular);
}

Javascript

function CheckGenesisFee(genesis, feeSatoshis, outputsSatoshis, scriptPubKeys, scriptsAreHex)
{
    // genesis is a CoinSparkGenesis object, already extracted from the transaction.
    // feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
    // outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
    // scriptPubKeys is an array containing each output script of a transaction, so that
    // the transaction has scriptPubKeys.length outputs.
    // Depending on scriptsAreHex, scriptPubKeys contains hex strings or Uint8Arrays of raw data.

    var countOutputs=scriptPubKeys.length; // must equal outputsSatoshis.length
    var outputsRegular=[];

    for (var output=0; output<countOutputs; output++)
        outputsRegular[output]=CoinSparkScriptIsRegular(scriptPubKeys[output], scriptsAreHex);

    return feeSatoshis>=genesis.calcMinFee(outputsSatoshis, outputsRegular);
}

PHP

function CheckGenesisFee($genesis, $feeSatoshis, $outputsSatoshis, $scriptPubKeys, $scriptsAreHex)
{
    // $genesis is a CoinSparkGenesis object, already extracted from the transaction.
    // $feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
    // $outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
    // $scriptPubKeys is an array containing each output script of a transaction, so that
    // the transaction has count($scriptPubKeys) outputs.
    // Depending on $scriptsAreHex, $scriptPubKeys contains hex strings or raw binary data.

    $countOutputs=count($scriptPubKeys); // must equal count($outputsSatoshis)
    $outputsRegular=array();

    for ($output=0; $output<$countOutputs; $output++)
        $outputsRegular[$output]=CoinSparkScriptIsRegular($scriptPubKeys[$output], $scriptsAreHex);

    return $feeSatoshis>=$genesis->calcMinFee($outputsSatoshis, $outputsRegular);
}

Python

def CheckGenesisFee(genesis, feeSatoshis, outputsSatoshis, scriptPubKeys, scriptsAreHex):
    # genesis is a CoinSparkGenesis object, already extracted from the transaction.
    # feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
    # outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
    # scriptPubKeys is an array containing each output script of a transaction, so that
    # the transaction has len(scriptPubKeys) outputs.
    # Depending on scriptsAreHex, scriptPubKeys contains hex strings or raw binary data.

    outputsRegular=[CoinSparkScriptIsRegular(script, scriptsAreHex) for script in scriptPubKeys]

    return feeSatoshis>=genesis.calcMinFee(outputsSatoshis, outputsRegular)

Ruby

def CheckGenesisFee(genesis, feeSatoshis, outputsSatoshis, scriptPubKeys, scriptsAreHex)
    # genesis is a CoinSparkGenesis object, already extracted from the transaction.
    # feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
    # outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
    # scriptPubKeys is an array containing each output script of a transaction, so that
    # the transaction has scriptPubKeys.length outputs.
    # Depending on scriptsAreHex, scriptPubKeys contains hex strings or raw binary data.

    outputsRegular=scriptPubKeys.map { |script| CoinSparkScriptIsRegular(script, scriptsAreHex) }

    return feeSatoshis>=genesis.calcMinFee(outputsSatoshis, outputsRegular)
end

Checking if transfer metadata has a sufficient fee

C/C++

bool CheckTransfersFee(const CoinSparkTransfer* transfers, const int countTransfers,
    const CoinSparkSatoshiQty feeSatoshis, const CoinSparkSatoshiQty* outputsSatoshis,
    const char* scriptPubKeys[], const size_t scriptPubKeysLen[], const bool scriptsAreHex,
    const int countInputs, const int countOutputs)
{
    // transfers is an array of CoinSparkTransfer structures, already extracted from the transaction.
    // countTransfers is the number of elements in the transfers array.
    // feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
    // outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
    // scriptPubKeys is an array of pointers to each output script of the transaction.
    // Depending on scriptsAreHex, scriptPubKeys contains hex strings or raw binary data.
    // scriptPubKeysLen is an array of byte lengths for each element of scriptPubKeys.

    bool *outputsRegular;
    int output;
    CoinSparkSatoshiQty minFeeSatoshis;

    outputsRegular=(bool*)malloc(countOutputs*bool);

    for (output=0; output<countOutputs; output++)
        outputsRegular[output]=CoinSparkScriptIsRegular(scriptPubKeys[output],
            scriptPubKeysLen[output], scriptsAreHex);

    minFeeSatoshis=CoinSparkTransfersCalcMinFee(transfers, countTransfers,
        countInputs, countOutputs, outputsSatoshis, outputsRegular);

    free(outputsRegular);

    return feeSatoshis>=minFeeSatoshis;
}

Java

// public static boolean CheckTransfersFee(CoinSparkTransferList transferList, long feeSatoshis,
//     long[] outputsSatoshis, byte[][] scriptPubKeys, int countInputs)

public static boolean CheckTransfersFee(CoinSparkTransferList transferList, long feeSatoshis,
    long[] outputsSatoshis, String[] scriptPubKeys, int countInputs)
{
    // transferList is a CoinSparkTransferList object, already extracted from the transaction.
    // feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
    // outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
    // scriptPubKeys is an array containing each output script of a transaction as a hex string
    // or raw binary (commented above), so that the transaction has scriptPubKeys.length outputs
    // and countInputs inputs.

    int countOutputs=scriptPubKeys.length;
    boolean[] outputsRegular=new boolean[countOutputs];

    for (int output=0; output<countOutputs; output++)
        outputsRegular[output]=CoinSparkBase.scriptIsRegular(scriptPubKeys[output]);

    return feeSatoshis>=transferList.calcMinFee(countInputs, outputsSatoshis, outputsRegular);
}

Javascript

function CheckTransfersFee(transferList, feeSatoshis, outputsSatoshis,
    scriptPubKeys, scriptsAreHex, countInputs)
{
    // transferList is a CoinSparkTransferList object, already extracted from the transaction.
    // feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
    // outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
    // scriptPubKeys is an array containing each output script of a transaction, so that
    // the transaction has scriptPubKeys.length outputs and countInputs inputs.
    // Depending on scriptsAreHex, scriptPubKeys contains hex strings or Uint8Arrays of raw data.

    var countOutputs=scriptPubKeys.length; // must equal outputsSatoshis.length
    var outputsRegular=[];
 
    for (var output=0; output<countOutputs; output++)
        outputsRegular[output]=CoinSparkScriptIsRegular(scriptPubKeys[output], scriptsAreHex);
 
    return feeSatoshis>=transferList.calcMinFee(countInputs, outputsSatoshis, outputsRegular);
}

PHP

function CheckTransfersFee($transferList, $feeSatoshis, $outputsSatoshis,
    $scriptPubKeys, $scriptsAreHex, $countInputs)
{
    // $transferList is a CoinSparkTransferList object, already extracted from the transaction.
    // $feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
    // $outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
    // $scriptPubKeys is an array containing each output script of a transaction, so that
    // the transaction has count($scriptPubKeys) outputs and $countInputs inputs.
    // Depending on $scriptsAreHex, $scriptPubKeys contains hex strings or raw binary data.

    $countOutputs=count($scriptPubKeys); // must equal count($outputsSatoshis)
    $outputsRegular=array();

    for ($output=0; $output<$countOutputs; $output++)
        $outputsRegular[$output]=CoinSparkScriptIsRegular($scriptPubKeys[$output], $scriptsAreHex);

    return $feeSatoshis>=$transferList->calcMinFee($countInputs, $outputsSatoshis, $outputsRegular);
}

Python

def CheckTransfersFee(transferList, feeSatoshis, outputsSatoshis, scriptPubKeys, scriptsAreHex, countInputs):
    # transferList is a CoinSparkTransferList object, already extracted from the transaction.
    # feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
    # outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
    # scriptPubKeys is an array containing each output script of a transaction, so that
    # the transaction has len(scriptPubKeys) outputs and countInputs inputs.
    # Depending on scriptsAreHex, scriptPubKeys contains hex strings or raw binary data.
    
    outputsRegular=[CoinSparkScriptIsRegular(script, scriptsAreHex) for script in scriptPubKeys]

    return feeSatoshis>=transferList.calcMinFee(countInputs, outputsSatoshis, outputsRegular)

Ruby

def CheckTransfersFee(transferList, feeSatoshis, outputsSatoshis, scriptPubKeys, scriptsAreHex, countInputs)
    # transferList is a CoinSparkTransferList object, already extracted from the transaction.
    # feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
    # outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
    # scriptPubKeys is an array containing each output script of a transaction, so that
    # the transaction has scriptPubKeys.length outputs and countInputs inputs.
    # Depending on scriptsAreHex, scriptPubKeys contains hex strings or raw binary data.
    
    outputsRegular=scriptPubKeys.map { |script| CoinSparkScriptIsRegular(script, scriptsAreHex) }

    return feeSatoshis>=transferList.calcMinFee(countInputs, outputsSatoshis, outputsRegular)
end