Skip to content

Commit

Permalink
Merge branch 'amber-dev' of http://github.com/ambertime/amberchain in…
Browse files Browse the repository at this point in the history
…to amber-dev
  • Loading branch information
miozzz committed Oct 3, 2018
2 parents 115c31a + 413ac49 commit 18d6e8f
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 43 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ AmberChain is based on the popular open source [MultiChain](http://www.multichai

## Documentation

Details on the API calls developed for AmberTime Blockhain can be found [here](https://github.com/ambertime/amberchain/blob/amber-dev/docs/AmberTime%20Blockchain%20Documentation_v1.0.pdf).
Details on the API calls developed for AmberTime Blockhain can be found [here](https://github.com/ambertime/amberchain/blob/amber-dev/docs/AmberTime%20Blockchain%20Documentation_v1.3.pdf).

## Setup instructions

Expand Down Expand Up @@ -48,6 +48,8 @@ Refer to the original multichain instructions [here](multichain-README.md)
Compile Amberchain for Ubuntu (64-bit)
```python
# amberchain/src >
./autogen.sh
./configure
make
# this will take a few minutes to build the chain
```
Expand Down
Binary file modified docs/AmberTime Blockchain Documentation_v1.0.pdf
Binary file not shown.
Binary file added docs/AmberTime Blockchain Documentation_v1.1.pdf
Binary file not shown.
Binary file added docs/AmberTime Blockchain Documentation_v1.2.pdf
Binary file not shown.
Binary file added docs/AmberTime Blockchain Documentation_v1.3.pdf
Binary file not shown.
24 changes: 24 additions & 0 deletions src/amber/streamutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,30 @@ namespace StreamUtils {
return adminFeeRatioValue;
}

bool IsPublicAccount(string address) {
if (!IsStreamExisting(STREAM_TRANSACTIONPARAMS)) {
return false;
}

Array streamParams;
streamParams.push_back(STREAM_TRANSACTIONPARAMS);
streamParams.push_back(KEY_PUBLICACCOUNT);
Array streamItems = liststreamkeyitems(streamParams, false).get_array();

if (streamItems.size() == 0) {
// return PermissionUtils::GetFirstAdminPublicKeyFromPermissions();
return false;
}

Object latestEntry = streamItems.back().get_obj();
string latestValueString = HexToStr(latestEntry[2].value_.get_str());

LogPrint("ambr", "ambr-test: public-account HEXTOSTR(%s) \n", latestValueString);

return strcmp(latestValueString.c_str(), address.c_str()) == 0;
}


bool IsStreamExisting(string streamName) {
try {
Array streamParams;
Expand Down
1 change: 1 addition & 0 deletions src/amber/streamutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace StreamUtils {
unsigned int GetMinimumRelayTxFee();
string GetAdminPublicKey();
double GetAdminFeeRatio();
bool IsPublicAccount(string address);
bool IsStreamExisting(string streamName);
}

Expand Down
1 change: 1 addition & 0 deletions src/amber/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#define KEY_TRANSACTIONFEE "min-relay-tx-fee"
#define KEY_ADMINPUBLICKEY "admin-public-key"
#define KEY_ADMINFEERATIO "admin-fee-ratio"
#define KEY_PUBLICACCOUNT "public-account"

using namespace std;

Expand Down
25 changes: 1 addition & 24 deletions src/amber/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,30 +185,7 @@ vector<CBitcoinAddress> scriptPubKey2Addresses(const CScript& scriptPubKey)
// TODO: Merge this with txsenderisminer
bool IsMinerTx(const CTransaction& tx)
{
if (tx.IsCoinBase())
{
return false;
}
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
CTransaction prevTx;
uint256 hashBlock = 0;
if (!GetTransaction(txin.prevout.hash, prevTx, hashBlock, true))
{
LogPrintf("IsMinerTx(): Previous transaction could not be retrieved.\n");
return false;
}
CScript scriptPubKey = prevTx.vout[txin.prevout.n].scriptPubKey;
BOOST_FOREACH(const CBitcoinAddress address, scriptPubKey2Addresses(scriptPubKey))
{
if (!haspermission(address.ToString(), "mine") && !multisighaspermission(address.ToString(), "mine")) {
// all from address must be miners or a multisig with one of the signers is a miner
return false;
}
}
}

return true;
return txsenderisminer(tx);
}

// custom transaction validation entry point, for future customisation support
Expand Down
29 changes: 29 additions & 0 deletions src/rpc/rpchelp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4125,6 +4125,35 @@ void mc_InitRPCHelpMap17()
"\nExample:\n"
+ HelpExampleCli("addservicequantity", "1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd 5d06edd7a0dbd0d83478c25fbf30cf3f07ceac45d9ced1591f6bd982fb878647 100")
));
mapHelpStrings.insert(std::make_pair("purchasenonconsumableservice",
"purchasenonconsumableservice\n"
"\nSends the amount to the receiver (escrow or seller), and records the purchase in purchasestatus stream.\n"
"\nArguments:\n"
"1. \"from-address\" (string, required) Address, must be address of service buyer\n"
"2. \"txid\" (string, required) Transaction ID of the service being purchased\n"
"3. \"service-name\" (string, required) Name of the service\n"
"4. \"amount\" (string, required) The total amount that the buyer has to pay in order to purchase the service\n"
"5. \"badge-notes-creator\" (string, optional) Badge notes that is encrypted for the badge creator\n"
"6. \"badge-notes-seller\" (string, optional) Badge notes that is encrypted for the badge seller\n"
"7. \"quantity\" (string, optional) Quantity, if buyer is purchasing multiple instances of the service \n"
"\nExample:\n"
+ HelpExampleCli("purchasenonconsumableservice", "1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd 5d06edd7a0dbd0d83478c25fbf30cf3f07ceac45d9ced1591f6bd982fb878647 servicename 1000 '' '' 1")
));
mapHelpStrings.insert(std::make_pair("purchaseconsumableservice",
"purchaseconsumableservice\n"
"\Records the purchase to the purchasestatus stream.\n"
"\nArguments:\n"
"1. \"from-address\" (string, required) Address, must be address of service buyer\n"
"2. \"txid\" (string, required) Transaction ID of the service being purchased\n"
"3. \"service-name\" (string, required) Name of the service\n"
"4. \"amount\" (string, required) The total amount that the buyer has to pay in order to purchase the service\n"
"5. \"quantity\" (string, optional) The quantity of service being purchased\n"
"6. \"escrow-address\" (string, optional) Escrow address, if service has an expiration date defined\n"
"7. \"badge-notes-creator\" (string, optional) Badge notes that is encrypted for the badge creator\n"
"8. \"badge-notes-seller\" (string, optional) Badge notes that is encrypted for the badge seller\n"
"\nExample:\n"
+ HelpExampleCli("purchaseconsumableservice", "1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd 5d06edd7a0dbd0d83478c25fbf30cf3f07ceac45d9ced1591f6bd982fb878647 servicename 1000 5 1AN7chsRuUyEtQGgZEDJs3eNBrAapzY2Ab'' '' 0")
));
mapHelpStrings.insert(std::make_pair("updatepurchasestatus",
"updatepurchasestatus\n"
"\nWrites the purchase status to the purchase status stream.\n"
Expand Down
9 changes: 7 additions & 2 deletions src/rpc/rpcpermissions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "rpc/rpcwallet.h"
#include "utils/utilstrencodings.h"
#include "amber/utils.h"

#include "amber/streamutils.h"

string AllowedPermissions()
{
Expand Down Expand Up @@ -524,8 +524,13 @@ bool multisighaspermission(std::string address, std::string permission)
}

// check that all of the tx inputs must be either from miners or from multisig where at least 1 signatory is a miner
// this is used to determine if the tx should be charged a tx fee
bool txsenderisminer(const CTransaction& tx)
{
if (tx.IsCoinBase())
{
return false;
}
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
uint256 prevTxHash = txin.prevout.hash;
Expand Down Expand Up @@ -555,7 +560,7 @@ bool txsenderisminer(const CTransaction& tx)
{
std::string address = CBitcoinAddress(addr).ToString();
// all input addresses must be miners or multisig with miner participation
if (!haspermission(address, "mine") && !multisighaspermission(address, "mine"))
if (!haspermission(address, "mine") && !multisighaspermission(address, "mine") && !StreamUtils::IsPublicAccount(address))
{
return false;
}
Expand Down
80 changes: 74 additions & 6 deletions src/rpc/rpcstreams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2818,6 +2818,7 @@ bool is_number(const std::string& s)
// param4 - total amount
// param5 - badge notes, encrypted for badge creator (optional)
// param6 - badge notes, encrypted for seller (optional)
// param7 - user-defined quantity (optional)
Value purchasenonconsumableservice(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 4)
Expand All @@ -2834,6 +2835,20 @@ Value purchasenonconsumableservice(const Array& params, bool fHelp)
amount = params[3].get_real();
}

// support either string or number for param7
int qty = 1;
if (params.size() > 6)
{
if (params[7].type() == str_type)
{
qty = atoi(params[7].get_str().c_str());
}
if (params[7].type() == int_type)
{
qty = params[7].get_int();
}
}

Array service_params;
service_params.push_back(STREAM_SERVICES);
service_params.push_back(params[1]);
Expand All @@ -2851,7 +2866,8 @@ Value purchasenonconsumableservice(const Array& params, bool fHelp)
purchase_data.push_back(Pair("selleraddress", publisher));
purchase_data.push_back(Pair("buyeraddress", params[0]));
purchase_data.push_back(Pair("amount", amount));
purchase_data.push_back(Pair("quantity", "0"));
purchase_data.push_back(Pair("quantity", "0")); // identifier in purchase completion if service is a nonconsumable service
purchase_data.push_back(Pair("userdefined_quantity", qty)); // record the number of instances purchased
if (params.size() > 4) {
purchase_data.push_back(Pair("badgenotescreator", params[4]));
}
Expand Down Expand Up @@ -3330,10 +3346,20 @@ Value appendrawsendfrom(const Array& params, bool fHelp)
std::string rawtx = params[0].get_str();
// we estimate that this function will add around 500 bytes to the TX (generous allowance)
unsigned int nSize = rawtx.length() + 500;
char msg[3000];

// estimate the needed tx fee
unsigned int minRelayTxFee = StreamUtils::GetMinimumRelayTxFee();
unsigned int estFee = minRelayTxFee*nSize / 1000;
std::string address = params[1].get_str();
if (haspermission(address, "mine") || multisighaspermission(address, "mine"))
{
// miners dont need no fee
estFee = 0;
}

Array accumulatedTransactionsArr;
unsigned int accumulatedAmount = 0;

// look for an unspent item that covers the needed fee
BOOST_FOREACH(const Value& data, unspentItems)
Expand All @@ -3342,23 +3368,46 @@ Value appendrawsendfrom(const Array& params, bool fHelp)
std::string txid;
int vout = 0;
bool amountFound = false;
bool smallerAmountFound = false;
BOOST_FOREACH(const Pair& d, results)
{
if (d.name_ == "txid") {
if (d.name_ == "txid")
{
txid = d.value_.get_str();
}
if (d.name_ == "vout") {
if (d.name_ == "vout")
{
vout = d.value_.get_int();
}
if (d.name_ == "amount") {
if (d.name_ == "amount")
{
// convert amount to satoshis
unsigned int satoshis = d.value_.get_real()*10000000; // multiplier is fixed for amberchain
if (satoshis >= estFee) {
if (satoshis >= estFee)
{
amountFound = true;
}
else
{
// accumulate smaller amounts if possible
if (accumulatedAmount < estFee)
{
accumulatedAmount += satoshis;
smallerAmountFound = true;
}
}
}
}
if (amountFound) {
if (smallerAmountFound)
{
sprintf(msg+strlen(msg),"\naccumulating an input!: %s.",txid.c_str());
Object transactionObj;
transactionObj.push_back(Pair("txid", txid));
transactionObj.push_back(Pair("vout", vout));
accumulatedTransactionsArr.push_back(transactionObj);
}
if (amountFound)
{
// build a raw transaction from the chosen txid and vout
Array transactionsArr;
Object transactionObj;
Expand All @@ -3377,6 +3426,25 @@ Value appendrawsendfrom(const Array& params, bool fHelp)
return appendrawchange(ext_params2, fHelp);
}
}

// we exited the loop without finding a single input that satisfies the est fee
// let's see if we have accumulated smaller inputs instead
sprintf(msg+strlen(msg),"\naccumulatedAmount: %d.",accumulatedAmount);
if (accumulatedAmount >= estFee)
{
Array ext_params;
ext_params.push_back(rawtx); // rawtx
ext_params.push_back(accumulatedTransactionsArr); // UTXOs
std::string appendedrawtx = appendrawtransaction(ext_params, fHelp).get_str();

Array ext_params2;
ext_params2.push_back(appendedrawtx); // rawtx
ext_params2.push_back(params[1]); // change address
return appendrawchange(ext_params2, fHelp);
}

sprintf(msg+strlen(msg),"\nInsufficient funds (appendrawsendfrom): %d.",estFee);
LogPrintf(msg);

// we can't find any valid UTXOs to spend, return error
throw JSONRPCError(RPC_INVALID_PARAMETER, "Insufficient funds.");
Expand Down
24 changes: 14 additions & 10 deletions src/rpc/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1178,11 +1178,13 @@ Value getauthmultisigaddress(const Array& params, bool fHelp)
for(int i = 0; i < list_auth.get_array().size(); i++)
{
std::string auth_address = list_auth.get_array()[i].get_obj()[0].value_.get_str();

Array pubkey_params;
pubkey_params.push_back(auth_address);
std::string auth_pubkey = getpubkeyforaddress(pubkey_params, false).get_str();
auth_pubkeys.push_back(auth_pubkey);
if (haspermission(auth_address, "mine"))
{
Array pubkey_params;
pubkey_params.push_back(auth_address);
std::string auth_pubkey = getpubkeyforaddress(pubkey_params, false).get_str();
auth_pubkeys.push_back(auth_pubkey);
}
}

int truesigsrequired = sigsrequired;
Expand Down Expand Up @@ -1240,11 +1242,13 @@ Value getescrowmultisigaddress(const Array& params, bool fHelp)
for(int i = 0; i < list_auth.get_array().size(); i++)
{
std::string auth_address = list_auth.get_array()[i].get_obj()[0].value_.get_str();

Array pubkey_params;
pubkey_params.push_back(auth_address);
std::string auth_pubkey = getpubkeyforaddress(pubkey_params, false).get_str();
pubkeys.push_back(auth_pubkey);
if (haspermission(auth_address, "mine"))
{
Array pubkey_params;
pubkey_params.push_back(auth_address);
std::string auth_pubkey = getpubkeyforaddress(pubkey_params, false).get_str();
pubkeys.push_back(auth_pubkey);
}
}

int truesigsrequired = sigsrequired;
Expand Down

0 comments on commit 18d6e8f

Please sign in to comment.