diff --git a/README.md b/README.md index 92917391..c3a7db25 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ Compile MultiChain for Mac (64-bit) export LDFLAGS=-L/usr/local/opt/openssl/lib export CPPFLAGS=-I/usr/local/opt/openssl/include + ./autogen.sh ./configure --with-gui=no --with-libs=no --with-miniupnpc=no make diff --git a/src/Makefile.am b/src/Makefile.am index f183bfe9..95ab04dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -179,6 +179,7 @@ libbitcoin_server_a_SOURCES = \ core/main.cpp \ protocol/multichaintx.cpp \ protocol/multichainblock.cpp \ + custom/custom_server.cpp \ protocol/handshake.cpp \ chain/merkleblock.cpp \ miner/miner.cpp \ @@ -252,6 +253,8 @@ multichain_libbitcoin_multichain_a_SOURCES = \ utils/tools.cpp \ utils/utilwrapper.cpp \ version/version.cpp \ + custom/custom.cpp \ + custom/custom_multichain.cpp \ chainparams/params.cpp \ protocol/multichainscript.cpp \ utils/dbwrapper.cpp \ @@ -513,6 +516,8 @@ libbitcoinconsensus_la_SOURCES = \ utils/utilwrapper.cpp \ chainparams/buildgenesis.cpp \ version/version.cpp \ + custom/custom.cpp \ + custom/custom_multichain.cpp \ chainparams/chainparams.cpp \ protocol/multichainscript.cpp \ utils/dbwrapper.cpp \ diff --git a/src/chainparams/chainparams.cpp b/src/chainparams/chainparams.cpp index 4f3d3059..8ea27db7 100644 --- a/src/chainparams/chainparams.cpp +++ b/src/chainparams/chainparams.cpp @@ -554,6 +554,14 @@ class CMultiChainParams : public CMainParams { } } + void SetMultiChainParam(const char*param_name,int64_t value) + { + if(strcmp(param_name,"targetblocktime") == 0) + { + nTargetSpacing=value; + } + } + void SetMultiChainRuntimeParams() { fMineBlocksOnDemand = GetBoolArg("-mineblocksondemand", false); @@ -781,6 +789,12 @@ void SetMultiChainParams() multiChainParams.SetMultiChainParams(); } +void SetMultiChainParam(const char*param_name,int64_t value) +{ + multiChainParams.SetMultiChainParam(param_name,value); +} + + void SetMultiChainRuntimeParams() { multiChainParams.SetMultiChainRuntimeParams(); diff --git a/src/chainparams/chainparams.h b/src/chainparams/chainparams.h index 51319d92..bd463178 100644 --- a/src/chainparams/chainparams.h +++ b/src/chainparams/chainparams.h @@ -166,6 +166,7 @@ bool SelectParamsFromCommandLine(); bool SelectMultiChainParams(const char *NetworkName); bool InitializeMultiChainParams(); void SetMultiChainParams(); +void SetMultiChainParam(const char*param_name,int64_t value); void SetMultiChainRuntimeParams(); diff --git a/src/chainparams/globals.h b/src/chainparams/globals.h index 81e3471c..f3feff15 100644 --- a/src/chainparams/globals.h +++ b/src/chainparams/globals.h @@ -11,12 +11,15 @@ unsigned int MAX_BLOCK_SIZE = 1000000; unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000; // main.h unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // main.h unsigned int MAX_STANDARD_TX_SIZE = 100000; // main.h +unsigned int MAX_BLOCK_SIGOPS = 20000; // main.h +unsigned int MAX_TX_SIGOPS = 4000; // main.h int COINBASE_MATURITY = 100; // main.h unsigned int MAX_SIZE = 0x02000000; // serialize,h int64_t COIN = 100000000; // amount.h int64_t CENT = 1000000; // amount.h int64_t MAX_MONEY = 21000000 * COIN; // amount.h unsigned int MAX_SCRIPT_ELEMENT_SIZE=520; // script.h +int MIN_BLOCKS_BETWEEN_UPGRADES = 100; int MAX_OP_RETURN_SHOWN=16384; int MAX_FORMATTED_DATA_DEPTH=100; unsigned int MAX_OP_RETURN_OP_DROP_COUNT=100000000; diff --git a/src/chainparams/paramlist.h b/src/chainparams/paramlist.h index 0293322c..52035c70 100644 --- a/src/chainparams/paramlist.h +++ b/src/chainparams/paramlist.h @@ -13,7 +13,7 @@ static const mc_OneMultichainParam MultichainParamArray[] = { "chaindescription" , "chain-description" , MC_PRM_STRING | MC_PRM_USER | MC_PRM_CLONE | MC_PRM_SPECIAL ,256, 0, 0, 0, 0.0, 10001, 0, "-mc-chaindescription", "rootstreamname","", - "Chain description, embedded in genesis block coinbase, max 256 chars."}, + "Chain description, embedded in genesis block coinbase, max 90 chars."}, { "rootstreamname" , "root-stream-name" , MC_PRM_STRING | MC_PRM_USER | MC_PRM_CLONE | MC_PRM_SPECIAL,256, 0, 0, 0, 0.0, 10006, 0, "-mc-rootstreamname", "rootstreamopen","", @@ -27,13 +27,17 @@ static const mc_OneMultichainParam MultichainParamArray[] = "targetblocktime","", "Content of the 'testnet' field of API responses, for compatibility."}, { "targetblocktime" , "target-block-time" , - MC_PRM_UINT32 | MC_PRM_USER | MC_PRM_CLONE , -1, 15, 2, 86400, 0.0, 10001, 0, "-mc-targetblocktime", + MC_PRM_UINT32 | MC_PRM_USER | MC_PRM_CLONE | MC_PRM_TIME , -1, 15, 2, 86400, 0.0, 10001, 0, "-mc-targetblocktime", "maximumblocksize","", "Target time between blocks (transaction confirmation delay), seconds."}, { "maximumblocksize" , "maximum-block-size" , - MC_PRM_UINT32 | MC_PRM_USER | MC_PRM_CLONE , -1, 8388608, 1000,1000000000, 0.0, 10001, 0, "-mc-maximumblocksize", - "defaultnetworkport","", + MC_PRM_UINT32 | MC_PRM_USER | MC_PRM_CLONE , -1, 8388608, 5000,1000000000, 0.0, 10001, 0, "-mc-maximumblocksize", + "timingupgrademingap","", "Maximum block size in bytes."}, + { "timingupgrademingap" , "timing-upgrade-min-gap" , + MC_PRM_UINT32 | MC_PRM_USER | MC_PRM_CLONE | MC_PRM_HIDDEN , -1, 100, 1, 31536000, 0.0, 20002, 0, "-mc-timingupgrademingap", + "defaultnetworkport","", + "Minimal gap between time-related parameter upgrades. In blocks."}, { "defaultnetworkport" , "default-network-port" , MC_PRM_UINT32 | MC_PRM_GENERATED | MC_PRM_CLONE , -1, MC_DEFAULT_NETWORK_PORT, 1024, 65535, 0.0, 10001, 0, "-mc-defaultnetworkport", "defaultrpcport","", @@ -159,7 +163,7 @@ static const mc_OneMultichainParam MultichainParamArray[] = "firstblockreward","Native blockchain currency (likely not required)", "Initial block mining reward in raw native currency units."}, { "rewardhalvinginterval" , "reward-halving-interval" , - MC_PRM_UINT32 | MC_PRM_USER | MC_PRM_CLONE , -1, 52560000, 60,4294967295U, 0.0, 10001, 0, "-mc-rewardhalvinginterval", + MC_PRM_UINT32 | MC_PRM_USER | MC_PRM_CLONE , -1, 52560000, 60,1000000000, 0.0, 10001, 0, "-mc-rewardhalvinginterval", "rewardspendabledelay","", "Interval for halving of mining rewards, in blocks."}, { "rewardspendabledelay" , "reward-spendable-delay" , diff --git a/src/chainparams/params.cpp b/src/chainparams/params.cpp index a87d7017..14807a3f 100644 --- a/src/chainparams/params.cpp +++ b/src/chainparams/params.cpp @@ -18,14 +18,20 @@ int mc_OneMultichainParam::IsRelevant(int version) { int ret=1; - if(m_ProtocolVersion > version) + int relevant_version=mc_gState->RelevantParamProtocolVersion(); + if(relevant_version == 0) + { + relevant_version=version; + } + + if(m_ProtocolVersion > relevant_version) { ret=0; } if(m_Removed > 0) { - if(m_Removed <= version) + if(m_Removed <= relevant_version) { ret=0; } @@ -44,6 +50,7 @@ void mc_MultichainParams::Zero() m_Size=0; m_IsProtocolMultiChain=1; m_ProtocolVersion=0; + m_RelevantProtocolVersion=0; m_AssetRefSize=MC_AST_SHORT_TXID_SIZE; } @@ -95,6 +102,32 @@ int64_t mc_MultichainParams::GetInt64Param(const char *param) return mc_GetLE(ptr,size); } +double mc_MultichainParams::Int64ToDecimal(int64_t value) +{ + if(value < 0) + { + return -((double)(-value) / MC_PRM_DECIMAL_GRANULARITY); + } + return (double)value / MC_PRM_DECIMAL_GRANULARITY; +} + +int64_t mc_MultichainParams::DecimalToInt64(double value) +{ + return (int64_t)(value*MC_PRM_DECIMAL_GRANULARITY+mc_gState->m_NetworkParams->ParamAccuracy()); +} + +int mc_MultichainParams::GetParamFromScript(char* script,int64_t *value,int *size) +{ + char *ptr; + ptr=script; + ptr+=strlen(ptr)+1; + *size=(int)mc_GetLE(ptr,MC_PRM_PARAM_SIZE_BYTES); + ptr+=MC_PRM_PARAM_SIZE_BYTES; + *value=mc_GetLE(ptr,*size); + ptr+=*size; + return ptr-script; +} + double mc_MultichainParams::GetDoubleParam(const char *param) { int n=(int)mc_gState->m_NetworkParams->GetInt64Param(param); @@ -130,6 +163,112 @@ void* mc_MultichainParams::GetParam(const char *param,int* size) return m_lpData+offset; } +int mc_MultichainParams::IsParamUpgradeValueInRange(const mc_OneMultichainParam *param,int version,int64_t value) +{ + if(value >= param->m_MinIntegerValue) + { + if(value <= param->m_MaxIntegerValue) + { + return 1; + } + } + return 0; +} + +int mc_MultichainParams::CanBeUpgradedByVersion(const char *param,int version,int size) +{ + if(m_lpIndex == NULL) + { + return -MC_PSK_INTERNAL_ERROR; + } + int index=m_lpIndex->Get(param); + if(index<0) + { + return -MC_PSK_NOT_FOUND; + } + int offset=m_lpCoord[2 * index + 0]; + if(offset<0) + { + return -MC_PSK_NOT_FOUND; + } + + if(size > 0) + { + if(size != m_lpCoord[2 * index + 1]) + { + return -MC_PSK_WRONG_SIZE; + } + } + + if(version == 0) + { + return m_lpCoord[2 * index + 1]; + } + + if(strcmp(param,"maximumblocksize") == 0) + { + if(version >= 20002) + { + return m_lpCoord[2 * index + 1]; + } + } + + if(strcmp(param,"targetblocktime") == 0) + { + if(GetInt64Param("targetadjustfreq") >= 0) + { + if(version >= 20002) + { + return m_lpCoord[2 * index + 1]; + } + } + } + + if(strcmp(param,"maxstdtxsize") == 0) + { + if(version >= 20002) + { + return m_lpCoord[2 * index + 1]; + } + } + + if(strcmp(param,"maxstdopreturnscount") == 0) + { + if(version >= 20002) + { + return m_lpCoord[2 * index + 1]; + } + } + + if(strcmp(param,"maxstdopreturnsize") == 0) + { + if(version >= 20002) + { + return m_lpCoord[2 * index + 1]; + } + } + + if(strcmp(param,"maxstdopdropscount") == 0) + { + if(version >= 20002) + { + return m_lpCoord[2 * index + 1]; + } + } + + if(strcmp(param,"maxstdelementsize") == 0) + { + if(version >= 20002) + { + return m_lpCoord[2 * index + 1]; + } + } + + + + return 0; +} + int mc_MultichainParams::SetParam(const char *param,const char* value,int size) { @@ -447,6 +586,19 @@ double mc_MultichainParams::ParamAccuracy() } +const mc_OneMultichainParam *mc_MultichainParams::FindParam(const char* param) +{ + int i; + for(i=0;im_Name,param) == 0) + { + return MultichainParamArray+i; + } + } + return NULL; +} + int mc_MultichainParams::Read(const char* name) { return Read(name,0,NULL,0); @@ -460,6 +612,7 @@ int mc_MultichainParams::Read(const char* name,int argc, char* argv[],int create mc_OneMultichainParam *param; char *ptrData; const char *ptr; + unsigned char custom_param[8]; if(name == NULL) { @@ -694,7 +847,12 @@ int mc_MultichainParams::Read(const char* name,int argc, char* argv[],int create ptrData=m_lpData+offset+MC_PRM_PARAM_SIZE_BYTES; - ptr=(char*)lpDefaultParams->GetParam(param->m_Name,&size); + ptr=(char*)custom_get_blockchain_default(param->m_Name,&size,custom_param); + if(ptr == NULL) + { + ptr=(char*)lpDefaultParams->GetParam(param->m_Name,&size); + } + if(size) { memcpy(ptrData,ptr,size); @@ -1087,23 +1245,26 @@ int mc_MultichainParams::Validate() if(isGenerated) { m_Status=MC_PRM_STATUS_GENERATED; - iv=GetInt64Param("targetblocktime"); - if(iv>0) + dv=2*(double)GetInt64Param("rewardhalvinginterval"); + dv*=(double)GetInt64Param("initialblockreward"); + iv=GetInt64Param("firstblockreward"); + if(iv<0) { - dv=2*(double)GetInt64Param("rewardhalvinginterval")/(double)iv; - dv*=(double)GetInt64Param("initialblockreward"); - iv=GetInt64Param("firstblockreward"); - if(iv<0) - { - iv=GetInt64Param("initialblockreward"); - } - dv+=(double)iv; - if(dv > 9.e+18) - { - printf("Total mining reward over blockchain's history is more than 2^63 raw units. Please reduce initial-block-reward or reward-halving-interval.\n"); - return MC_ERR_INVALID_PARAMETER_VALUE; - } - } + iv=GetInt64Param("initialblockreward"); + } + dv+=(double)iv; + if(dv > 9.e+18) + { + printf("Total mining reward over blockchain's history is more than 2^63 raw units. Please reduce initial-block-reward or reward-halving-interval.\n"); + return MC_ERR_INVALID_PARAMETER_VALUE; + } + + GetParam("chaindescription",&size); + if(size-1 > 90) + { + printf("Invalid parameter value for chain-description - too long: %d\n",size-1); + return MC_ERR_INVALID_PARAMETER_VALUE; + } } else { @@ -1126,7 +1287,7 @@ int mc_MultichainParams::Print(FILE* fileHan) int i,c,size; int version; int header_printed; - int set,chars_remaining; + int set,chars_remaining,hidden; void *ptr; char line[MC_PRM_DAT_FILE_LINE_SIZE+1+100]; char *cptr; @@ -1184,6 +1345,7 @@ int mc_MultichainParams::Print(FILE* fileHan) if( (((m_lpParams+i)->m_Type & MC_PRM_SOURCE_MASK) == param_sets[set]) && ((m_lpParams+i)->IsRelevant(version) > 0)) { + hidden=0; if(header_printed == 0) { fprintf(fileHan,"\n"); @@ -1344,6 +1506,13 @@ int mc_MultichainParams::Print(FILE* fileHan) else { sprintf(line+strlen(line),"%ld",mc_GetLE(ptr,4)); + if((m_lpParams+i)->m_Type & MC_PRM_HIDDEN) + { + if(mc_GetLE(ptr,4) == (m_lpParams+i)->m_DefaultIntegerValue) + { + hidden=1; + } + } } break; case MC_PRM_INT64: @@ -1358,76 +1527,79 @@ int mc_MultichainParams::Print(FILE* fileHan) { sprintf(line+strlen(line),"[null]"); } - if(chars_remaining == 0) - { - fprintf(fileHan,"%s",line); - chars_remaining=MC_PRM_DAT_FILE_LINE_SIZE-strlen(line)+1; - } - for(c=0;cm_Description; - while(*cptr) - { - c=0; - - while((c<(int)strlen(cptr)) && (cptr[c]!='\n')) + if(chars_remaining == 0) { - c++; + fprintf(fileHan,"%s",line); + chars_remaining=MC_PRM_DAT_FILE_LINE_SIZE-strlen(line)+1; } - - if(c<(int)strlen(cptr)) + for(c=0;cm_Description; + while(*cptr) { - fprintf(fileHan,"# %s",cptr); - cptr+=c; - } - } + c=0; - switch((m_lpParams+i)->m_Type & MC_PRM_DATA_TYPE_MASK) - { - case MC_PRM_INT32: - case MC_PRM_INT64: - case MC_PRM_UINT32: - switch(param_sets[set]) + while((c<(int)strlen(cptr)) && (cptr[c]!='\n')) { - case MC_PRM_COMMENT: - case MC_PRM_USER: - if((m_lpParams+i)->m_MinIntegerValue <= (m_lpParams+i)->m_MaxIntegerValue) - { - if((m_lpParams+i)->m_Type & MC_PRM_DECIMAL) + c++; + } + + if(c<(int)strlen(cptr)) + { + cptr[c]=0x00; + fprintf(fileHan,"# %s",cptr); + memset(line,0x20,MC_PRM_DAT_FILE_LINE_SIZE); + line[MC_PRM_DAT_FILE_LINE_SIZE]=0x00; + fprintf(fileHan,"\n%s ",line); + cptr+=c+1; + } + else + { + fprintf(fileHan,"# %s",cptr); + cptr+=c; + } + } + + switch((m_lpParams+i)->m_Type & MC_PRM_DATA_TYPE_MASK) + { + case MC_PRM_INT32: + case MC_PRM_INT64: + case MC_PRM_UINT32: + switch(param_sets[set]) + { + case MC_PRM_COMMENT: + case MC_PRM_USER: + if((m_lpParams+i)->m_MinIntegerValue <= (m_lpParams+i)->m_MaxIntegerValue) { - d1=0; - if((m_lpParams+i)->m_MinIntegerValue) + if((m_lpParams+i)->m_Type & MC_PRM_DECIMAL) { - d1=((double)((m_lpParams+i)->m_MinIntegerValue)+ParamAccuracy())/MC_PRM_DECIMAL_GRANULARITY; + d1=0; + if((m_lpParams+i)->m_MinIntegerValue) + { + d1=((double)((m_lpParams+i)->m_MinIntegerValue)+ParamAccuracy())/MC_PRM_DECIMAL_GRANULARITY; + } + d2=0; + if((m_lpParams+i)->m_MaxIntegerValue) + { + d2=((double)((m_lpParams+i)->m_MaxIntegerValue)+ParamAccuracy())/MC_PRM_DECIMAL_GRANULARITY; + } + fprintf(fileHan," (%0.6g - %0.6g)",d1,d2); } - d2=0; - if((m_lpParams+i)->m_MaxIntegerValue) + else { - d2=((double)((m_lpParams+i)->m_MaxIntegerValue)+ParamAccuracy())/MC_PRM_DECIMAL_GRANULARITY; + fprintf(fileHan," (%ld - %ld)",(m_lpParams+i)->m_MinIntegerValue,(m_lpParams+i)->m_MaxIntegerValue); } - fprintf(fileHan," (%0.6g - %0.6g)",d1,d2); - } - else - { - fprintf(fileHan," (%ld - %ld)",(m_lpParams+i)->m_MinIntegerValue,(m_lpParams+i)->m_MaxIntegerValue); } - } - break; - } - break; + break; + } + break; + } + fprintf(fileHan,"\n"); } - fprintf(fileHan,"\n"); } if(strlen((m_lpParams+i)->m_Next)) @@ -1543,6 +1715,10 @@ const unsigned char* mc_MultichainParams::AddressCheckumValue() int mc_MultichainParams::ProtocolVersion() { + if(mc_gState->m_NetworkParams->m_RelevantProtocolVersion) + { + return mc_gState->m_NetworkParams->m_RelevantProtocolVersion; + } if(m_ProtocolVersion) { return m_ProtocolVersion; @@ -1960,3 +2136,43 @@ int mc_Features::FixedIsUnspendable() return ret; } +int mc_Features::PerAssetPermissions() +{ + int ret=0; + if(mc_gState->m_NetworkParams->IsProtocolMultichain() == 0) + { + return 0; + } + int protocol=mc_gState->m_NetworkParams->ProtocolVersion(); + + if(protocol) + { + if(protocol >= 20002) + { + ret=1; + } + } + + return ret; +} + +int mc_Features::ParameterUpgrades() +{ + int ret=0; + if(mc_gState->m_NetworkParams->IsProtocolMultichain() == 0) + { + return 0; + } + int protocol=mc_gState->m_NetworkParams->ProtocolVersion(); + + if(protocol) + { + if(protocol >= 20002) + { + ret=1; + } + } + + return ret; +} + diff --git a/src/chainparams/params.h b/src/chainparams/params.h index 11b08a1c..08ee0d62 100644 --- a/src/chainparams/params.h +++ b/src/chainparams/params.h @@ -37,6 +37,8 @@ #define MC_PRM_NOHASH 0x00040000 #define MC_PRM_MINIMAL 0x00080000 #define MC_PRM_DECIMAL 0x00100000 +#define MC_PRM_HIDDEN 0x00200000 +#define MC_PRM_TIME 0x00400000 #define MC_PRM_STATUS_EMPTY 0 @@ -46,6 +48,20 @@ #define MC_PRM_STATUS_INVALID 4 #define MC_PRM_STATUS_VALID 5 +#define MC_PSK_APPLIED 0 +#define MC_PSK_INTERNAL_ERROR 1 +#define MC_PSK_NOT_FOUND 2 +#define MC_PSK_WRONG_SIZE 3 +#define MC_PSK_OUT_OF_RANGE 4 +#define MC_PSK_FRESH_UPGRADE 5 +#define MC_PSK_DOUBLE_RANGE 6 +#define MC_PSK_NOT_SUPPORTED 7 +#define MC_PSK_NEW_NOT_DOWNGRADABLE 8 +#define MC_PSK_OLD_NOT_DOWNGRADABLE 9 + + + + extern int MCP_MAX_STD_OP_RETURN_COUNT; extern int64_t MCP_INITIAL_BLOCK_REWARD; extern int64_t MCP_FIRST_BLOCK_REWARD; @@ -96,6 +112,7 @@ typedef struct mc_MultichainParams int m_Count; int m_IsProtocolMultiChain; int m_ProtocolVersion; + int m_RelevantProtocolVersion; int m_AssetRefSize; @@ -123,17 +140,24 @@ typedef struct mc_MultichainParams int Write(int overwrite); int Print(FILE *); int SetGlobals(); + int SetProtocolGlobals(); + int SetUpgradedParamValue(const mc_OneMultichainParam *param,int64_t value); int Import(const char *name,const char *source_address); int Set(const char *name,const char *source,int source_size); - int FindParam(const char *param); + const mc_OneMultichainParam *FindParam(const char *param); void* GetParam(const char *param,int* size); int64_t GetInt64Param(const char *param); double GetDoubleParam(const char *param); + double Int64ToDecimal(int64_t value); + int64_t DecimalToInt64(double value); + int GetParamFromScript(char* ptr,int64_t *value,int *size); int SetParam(const char *param,const char* value,int size); int SetParam(const char *param,int64_t value); + int CanBeUpgradedByVersion(const char *param,int version,int size); + int IsParamUpgradeValueInRange(const mc_OneMultichainParam *param,int version,int64_t value); const char* Name(); const unsigned char* DefaultMessageStart(); diff --git a/src/chainparams/state.h b/src/chainparams/state.h index e18d4ef4..98920cea 100644 --- a/src/chainparams/state.h +++ b/src/chainparams/state.h @@ -9,6 +9,7 @@ #include "protocol/multichainscript.h" #include "permissions/permission.h" #include "entities/asset.h" +#include "wallet/wallettxdb.h" #define MC_FAT_UNKNOWN 1 #define MC_FAT_COMMAND 2 @@ -32,6 +33,7 @@ #define MC_NPS_NETWORK 0x00000001 #define MC_NPS_INCOMING 0x00000002 #define MC_NPS_MINING 0x00000004 +#define MC_NPS_REACCEPT 0x00000008 #define MC_NPS_ALL 0xFFFFFFFF #define MC_WMD_NONE 0x00000000 @@ -106,6 +108,23 @@ typedef struct mc_Params } mc_Params; +typedef struct mc_UpgradeStatus +{ + unsigned char m_EntityShortTxID[MC_ENT_KEY_SIZE]; + uint32_t m_ApprovedBlock; + uint32_t m_AppliedBlock; + uint32_t m_FirstParam; + uint32_t m_LastParam; +} mc_UpgradeStatus; + +typedef struct mc_UpgradedParameter +{ + const mc_OneMultichainParam *m_Param; + int64_t m_Value; + uint32_t m_Block; + int32_t m_Skipped; +} mc_UpgradedParameter; + typedef struct mc_Features { int MinProtocolVersion(); @@ -130,6 +149,8 @@ typedef struct mc_Features int FixedIn1000920001(); int MultipleStreamKeys(); int FixedIsUnspendable(); + int PerAssetPermissions(); + int ParameterUpgrades(); } mc_Features; typedef struct mc_BlockHeaderInfo @@ -140,6 +161,64 @@ typedef struct mc_BlockHeaderInfo } mc_BlockHeaderInfo; +typedef struct mc_TmpBuffers +{ + mc_TmpBuffers() + { + Init(); + } + + ~mc_TmpBuffers() + { + Destroy(); + } + + mc_Script *m_RpcScript1; + mc_Script *m_RpcScript2; + mc_Script *m_RpcScript3; + mc_Script *m_RpcScript4; + mc_Buffer *m_RpcABBuffer1; + mc_Buffer *m_RpcABBuffer2; + mc_Buffer *m_RpcBuffer1; + mc_Buffer *m_RpcABNoMapBuffer1; + mc_Buffer *m_RpcABNoMapBuffer2; + mc_Buffer *m_RpcEntityRows; + + void Init() + { + m_RpcScript1=new mc_Script(); + m_RpcScript2=new mc_Script(); + m_RpcScript3=new mc_Script(); + m_RpcScript4=new mc_Script(); + m_RpcABBuffer1=new mc_Buffer; + mc_InitABufferMap(m_RpcABBuffer1); + m_RpcABBuffer2=new mc_Buffer; + mc_InitABufferMap(m_RpcABBuffer2); + m_RpcBuffer1=new mc_Buffer; + m_RpcABNoMapBuffer1=new mc_Buffer; + mc_InitABufferDefault(m_RpcABNoMapBuffer1); + m_RpcABNoMapBuffer2=new mc_Buffer; + mc_InitABufferDefault(m_RpcABNoMapBuffer2); + m_RpcEntityRows=new mc_Buffer; + m_RpcEntityRows->Initialize(MC_TDB_ENTITY_KEY_SIZE,MC_TDB_ROW_SIZE,MC_BUF_MODE_DEFAULT); + } + + void Destroy() + { + delete m_RpcScript1; + delete m_RpcScript2; + delete m_RpcScript3; + delete m_RpcScript4; + delete m_RpcABBuffer1; + delete m_RpcABBuffer2; + delete m_RpcBuffer1; + delete m_RpcABNoMapBuffer1; + delete m_RpcABNoMapBuffer2; + delete m_RpcEntityRows; + } + +} mc_TmpBuffers; + typedef struct mc_State { mc_State() @@ -165,14 +244,18 @@ typedef struct mc_State void *m_pSeedNode; uint32_t m_Compatibility; uint32_t m_SessionFlags; + unsigned char m_BurnAddress[20]; mc_Script *m_TmpScript; mc_Script *m_TmpScript1; mc_Buffer *m_TmpAssetsOut; mc_Buffer *m_TmpAssetsIn; + mc_Buffer *m_TmpAssetsTmp; mc_Buffer *m_BlockHeaderSuccessors; + mc_TmpBuffers *m_TmpBuffers; + void InitDefaults() { m_Params=new mc_Params; @@ -186,6 +269,7 @@ typedef struct mc_State m_NodePausedState=MC_NPS_NONE; m_ProtocolVersionToUpgrade=0; m_SessionFlags=MC_SSF_DEFAULT; + memset(m_BurnAddress,0,20); m_IPv4Address=0; m_WalletMode=0; @@ -193,6 +277,8 @@ typedef struct mc_State mc_InitABufferMap(m_TmpAssetsOut); m_TmpAssetsIn=new mc_Buffer; mc_InitABufferMap(m_TmpAssetsIn); + m_TmpAssetsTmp=new mc_Buffer; + mc_InitABufferMap(m_TmpAssetsTmp); m_Compatibility=MC_VCM_NONE; m_BlockHeaderSuccessors=new mc_Buffer; @@ -201,6 +287,8 @@ typedef struct mc_State memset(&bhi,0,sizeof(mc_BlockHeaderInfo)); m_BlockHeaderSuccessors->Add(&bhi); + m_TmpBuffers=new mc_TmpBuffers; + m_pSeedNode=NULL; } @@ -242,10 +330,18 @@ typedef struct mc_State { delete m_TmpAssetsIn; } + if(m_TmpAssetsTmp) + { + delete m_TmpAssetsTmp; + } if(m_BlockHeaderSuccessors) { delete m_BlockHeaderSuccessors; } + if(m_TmpBuffers) + { + delete m_TmpBuffers; + } } int VersionInfo(int version); @@ -254,6 +350,8 @@ typedef struct mc_State int GetProtocolVersion(); int MinProtocolVersion(); int MinProtocolDowngradeVersion(); + int MinProtocolForbiddenDowngradeVersion(); + int RelevantParamProtocolVersion(); int IsSupported(int version); int IsDeprecated(int version); const char* GetSeedNode(); diff --git a/src/core/init-cold.cpp b/src/core/init-cold.cpp index f237d404..45ec7255 100644 --- a/src/core/init-cold.cpp +++ b/src/core/init-cold.cpp @@ -218,6 +218,7 @@ std::string HelpMessage_Cold() strUsage += " -rpcport= " + strprintf(_("Listen for JSON-RPC connections on (default: %u or testnet: %u)"), 8332, 18332) + "\n"; strUsage += " -rpcallowip= " + _("Allow JSON-RPC connections from specified source. Valid for are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).") + "\n"; strUsage += " " + _("This option can be specified multiple times") + "\n"; + strUsage += " -rpcallowmethod= " + _("If specified, allow only comma delimited list of JSON-RPC . This option can be specified multiple times.") + "\n"; strUsage += " -rpcthreads= " + strprintf(_("Set the number of threads to service RPC calls (default: %d)"), 4) + "\n"; strUsage += " -rpckeepalive " + strprintf(_("RPC support for HTTP persistent connections (default: %d)"), 0) + "\n"; @@ -1013,6 +1014,13 @@ bool AppInit2_Cold(boost::thread_group& threadGroup,int OutputPipe) return false; } LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart); + + if(mapMultiArgs.count("-rpcallowip") == 0) + { + sprintf(bufOutput,"Listening for API requests on port %d (local only - see rpcallowip setting)\n\n",(int)GetArg("-rpcport", BaseParams().RPCPort())); + bytes_written=write(OutputPipe,bufOutput,strlen(bufOutput)); + } + int version=mc_gState->m_NetworkParams->ProtocolVersion(); LogPrintf("MultiChain protocol version: %d\n",version); @@ -1024,11 +1032,11 @@ bool AppInit2_Cold(boost::thread_group& threadGroup,int OutputPipe) if(version != original_protocol_version) { - sprintf(bufOutput,"Protocol version %d (chain created with %d)\n\n",version,original_protocol_version); + sprintf(bufOutput,"Chain running protocol version %d (chain created with %d)\n\n",version,original_protocol_version); } else { - sprintf(bufOutput,"Protocol version %d\n\n",version); + sprintf(bufOutput,"Chain running protocol version %d\n\n",version); } bytes_written=write(OutputPipe,bufOutput,strlen(bufOutput)); } @@ -1236,7 +1244,7 @@ bool AppInit2_Cold(boost::thread_group& threadGroup,int OutputPipe) /* MCHN START */ if(!GetBoolArg("-shortoutput", false)) { - sprintf(bufOutput,"Node started\n"); + sprintf(bufOutput,"Node ready.\n\n"); bytes_written=write(OutputPipe,bufOutput,strlen(bufOutput)); } mc_InitRPCHelpMap(); diff --git a/src/core/init.cpp b/src/core/init.cpp index 1ef1c53c..fd907707 100644 --- a/src/core/init.cpp +++ b/src/core/init.cpp @@ -318,6 +318,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += " -datadir= " + _("Specify data directory") + "\n"; strUsage += " -dbcache= " + strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache) + "\n"; strUsage += " -loadblock= " + _("Imports blocks from external blk000??.dat file") + " " + _("on startup") + "\n"; + strUsage += " -loadblockmaxsize= " + _("Maximal block size in the files specified in -loadblock") + "\n"; strUsage += " -maxorphantx= " + strprintf(_("Keep at most unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS) + "\n"; strUsage += " -par= " + strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), -(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS) + "\n"; #ifndef WIN32 @@ -384,6 +385,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + " " + _("on startup") + "\n"; strUsage += " -wallet= " + _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat") + "\n"; strUsage += " -walletnotify= " + _("Execute this command when a transaction is first seen or confirmed, if it relates to an address in the wallet or a subscribed asset or stream. ") + "\n"; + strUsage += " -walletnotifynew= " + _("Execute this command when a transaction is first seen, if it relates to an address in the wallet or a subscribed asset or stream. ") + "\n"; strUsage += " " + _("(more details and % substitutions online)") + "\n"; /* MCHN START */ strUsage += " -walletdbversion=1|2 " + _("Specify wallet version, 1 - not scalable, 2 (default) - scalable") + "\n"; @@ -464,6 +466,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += " -rpcport= " + strprintf(_("Listen for JSON-RPC connections on (default: %u or testnet: %u)"), 8332, 18332) + "\n"; strUsage += " -rpcallowip= " + _("Allow JSON-RPC connections from specified source. Valid for are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).") + "\n"; strUsage += " " + _("This option can be specified multiple times") + "\n"; + strUsage += " -rpcallowmethod= " + _("If specified, allow only comma delimited list of JSON-RPC . This option can be specified multiple times.") + "\n"; strUsage += " -rpcthreads= " + strprintf(_("Set the number of threads to service RPC calls (default: %d)"), 4) + "\n"; strUsage += " -rpckeepalive " + strprintf(_("RPC support for HTTP persistent connections (default: %d)"), 0) + "\n"; @@ -1049,6 +1052,8 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) bool fFirstRunForBuild; string init_privkey=GetArg("-initprivkey",""); + + mc_gState->m_NetworkParams->m_RelevantProtocolVersion=mc_gState->RelevantParamProtocolVersion(); // Caching relevant protocol version pwalletMain=NULL; if(mc_gState->m_NetworkParams->m_Status != MC_PRM_STATUS_VALID) @@ -1334,6 +1339,9 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) return InitError(_(seed_error.c_str())); } + string strBurnAddress=BurnAddress(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)); // Caching burn address + LogPrint("mchn","mchn: Burn address: %s\n",strBurnAddress.c_str()); + int64_t wallet_mode=GetArg("-walletdbversion",0); bool wallet_mode_valid=false; if(wallet_mode == 0) @@ -1385,6 +1393,7 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) case MC_TET_STREAM: case MC_TET_STREAM_KEY: case MC_TET_STREAM_PUBLISHER: + case MC_TET_ASSET: vSubscribedEntities.push_back(stat->m_Entity); break; } @@ -1864,7 +1873,7 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) bytes_written=write(OutputPipe,bufOutput,strlen(bufOutput)); if(found_ips > 1) { - sprintf(bufOutput,"\nThis host has multiple IP addresses, so from some networks:\n\n"); + sprintf(bufOutput,"This host has multiple IP addresses, so from some networks:\n"); bytes_written=write(OutputPipe,bufOutput,strlen(bufOutput)); for(int i_ips=0;i_ipsm_NetworkParams->GetInt64Param("protocolversion"); int version=mc_gState->m_NetworkParams->ProtocolVersion(); LogPrintf("MultiChain protocol version: %d\n",version); @@ -2143,11 +2158,11 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) if(version != original_protocol_version) { - sprintf(bufOutput,"Protocol version %d (chain created with %d)\n\n",version,original_protocol_version); + sprintf(bufOutput,"Chain running protocol version %d (chain created with %d)\n\n",version,original_protocol_version); } else { - sprintf(bufOutput,"Protocol version %d\n\n",version); + sprintf(bufOutput,"Chain running protocol version %d\n\n",version); } bytes_written=write(OutputPipe,bufOutput,strlen(bufOutput)); } @@ -2405,7 +2420,7 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) /* MCHN START */ if(!GetBoolArg("-shortoutput", false)) { - sprintf(bufOutput,"Node started\n"); + sprintf(bufOutput,"Node ready.\n\n"); bytes_written=write(OutputPipe,bufOutput,strlen(bufOutput)); } mc_InitRPCHelpMap(); diff --git a/src/core/main.cpp b/src/core/main.cpp index 168b1d64..292bd9e2 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -72,6 +72,7 @@ bool MultichainNode_AcceptData(CNode *pnode); bool MultichainNode_IgnoreIncoming(CNode *pnode); bool MultichainNode_IsLocal(CNode *pnode); bool IsTxBanned(uint256 txid); +int CreateUpgradeLists(int current_height,vector *vParams,vector *vUpgrades); @@ -347,7 +348,126 @@ map mapNodeState; /* MCHN START */ +int SetUpgradedParamValue(const mc_OneMultichainParam *param,int64_t value) +{ + if(mc_gState->m_Features->ParameterUpgrades() == 0) + { + return MC_ERR_NOERROR; + } + + if(strcmp(param->m_Name,"maximumblocksize") == 0) + { + MAX_BLOCK_SIZE=(unsigned int)value; + DEFAULT_BLOCK_MAX_SIZE=MAX_BLOCK_SIZE; + while(MAX_BLOCK_SIZE>MAX_BLOCKFILE_SIZE) + { + MAX_BLOCKFILE_SIZE *= 2; + } + while(MAX_BLOCK_SIZE>MAX_SIZE) + { + MAX_SIZE *= 2; + } + MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; + MAX_TX_SIGOPS = MAX_BLOCK_SIGOPS/5; + } + + if(strcmp(param->m_Name,"targetblocktime") == 0) + { + MCP_TARGET_BLOCK_TIME=value; + SetMultiChainParam("targetblocktime",value); + } + + if(strcmp(param->m_Name,"maxstdtxsize") == 0) + { + MAX_STANDARD_TX_SIZE=value; + } + + if(strcmp(param->m_Name,"maxstdopreturnscount") == 0) + { + MCP_MAX_STD_OP_RETURN_COUNT=value; + } + + if(strcmp(param->m_Name,"maxstdopreturnsize") == 0) + { + MAX_OP_RETURN_RELAY=value; + MAX_OP_RETURN_RELAY=GetArg("-datacarriersize", MAX_OP_RETURN_RELAY); + } + + if(strcmp(param->m_Name,"maxstdopdropscount") == 0) + { + MCP_STD_OP_DROP_COUNT=value; + pwalletMain->InitializeUnspentList(); + } + + if(strcmp(param->m_Name,"maxstdelementsize") == 0) + { + MAX_SCRIPT_ELEMENT_SIZE=value; + pwalletMain->InitializeUnspentList(); + } + + return MC_ERR_NOERROR; +} + int MultichainNode_ApplyUpgrades(int current_height) +{ + vector vParams; + int err=MC_ERR_NOERROR; + + err=CreateUpgradeLists(current_height,&vParams,NULL); + + int OriginalProtocolVersion=(int)mc_gState->m_NetworkParams->GetInt64Param("protocolversion"); + int CurrentProtocolVersion=mc_gState->m_NetworkParams->ProtocolVersion();//mc_gState->m_ProtocolVersionToUpgrade; + + mc_gState->m_NetworkParams->m_ProtocolVersion=OriginalProtocolVersion; + mc_gState->m_NetworkParams->SetGlobals(); + for(int p=0;p<(int)vParams.size();p++) + { + if(vParams[p].m_Skipped == MC_PSK_APPLIED) + { + if(strcmp(vParams[p].m_Param->m_Name,"protocolversion") == 0) + { + mc_gState->m_NetworkParams->m_ProtocolVersion=(int)vParams[p].m_Value; + mc_gState->m_NetworkParams->SetProtocolGlobals(); + } + else + { + SetUpgradedParamValue(vParams[p].m_Param,vParams[p].m_Value); + } + } + } + SetMultiChainParams(); + mc_gState->m_ProtocolVersionToUpgrade=mc_gState->m_NetworkParams->m_ProtocolVersion; + + + if(mc_gState->m_ProtocolVersionToUpgrade != CurrentProtocolVersion) + { + LogPrintf("New protocol upgrade version: %d (was %d)\n",mc_gState->m_ProtocolVersionToUpgrade,CurrentProtocolVersion); + if( (err == MC_ERR_NOT_SUPPORTED) || ((mc_gState->m_ProtocolVersionToUpgrade > 0) && (mc_gState->IsSupported(mc_gState->m_ProtocolVersionToUpgrade) == 0)) ) + { + mc_gState->m_NetworkParams->m_ProtocolVersion=CurrentProtocolVersion; + LogPrintf("NODE SHOULD BE UPGRADED FROM %d TO %d\n",mc_gState->GetProtocolVersion(),mc_gState->m_ProtocolVersionToUpgrade); + } + else + { + LogPrintf("NODE IS UPGRADED FROM %d TO %d\n",CurrentProtocolVersion,mc_gState->m_ProtocolVersionToUpgrade); +/* + if(mc_gState->m_ProtocolVersionToUpgrade != mc_gState->m_NetworkParams->ProtocolVersion()) + { + LogPrintf("NODE IS UPGRADED FROM %d TO %d\n",mc_gState->m_NetworkParams->ProtocolVersion(),mc_gState->m_ProtocolVersionToUpgrade); + } + */ + } + } + else + { + mc_gState->m_ProtocolVersionToUpgrade=0; + } + + return MC_ERR_NOERROR; +} + + +int MultichainNode_ApplyUpgrades_Old(int current_height) { mc_EntityDetails entity; mc_Buffer *permissions; @@ -393,7 +513,10 @@ int MultichainNode_ApplyUpgrades(int current_height) version=entity.UpgradeProtocolVersion(); if(version >= mc_gState->MinProtocolDowngradeVersion()) { - NewProtocolVersion=version; + if((NewProtocolVersion < mc_gState->MinProtocolForbiddenDowngradeVersion()) || (version >= NewProtocolVersion)) + { + NewProtocolVersion=version; + } } } } @@ -2225,6 +2348,15 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return false; } + if(!CheckBlockForUpgardableConstraints(block,state,"maximum-block-size",true)) + { + return false; + } + if(!CheckBlockForUpgardableConstraints(block,state,"maximum-block-sigops",true)) + { + return false; + } + /* MCHN START */ uint256 block_hash; unsigned char miner_address[20]; @@ -3258,8 +3390,11 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo if(fDebug)LogPrint("mcblockperf","mchn-block-perf: Reaccepting wallet transactions\n"); if(pwalletMain) { - pwalletMain->ReacceptWalletTransactions(); // Some wallet transactions may become invalid in reorg + if( (mc_gState->m_NodePausedState & MC_NPS_REACCEPT) == 0 ) + { + pwalletMain->ReacceptWalletTransactions(); // Some wallet transactions may become invalid in reorg // Some may become invalid if not confirmed in time + } } if(fDebug)LogPrint("mcblockperf","mchn-block-perf: Best chain activation completed\n"); @@ -3471,7 +3606,6 @@ string SetLastBlock(uint256 hash,bool *fNotFound) CBlockIndex *pindex; pindex=pblockindex; - while(pindex != pindexFork) { if (pblockindex->nStatus & BLOCK_FAILED_MASK) @@ -3503,12 +3637,16 @@ string SetLastBlock(uint256 hash,bool *fNotFound) pindex=pindex->pprev; } - if(!ActivateBestChainStep(state,pblockindex,&block)) + while(pblockindex != chainActive.Tip()) { - string error=state.GetRejectReason(); - ActivateBestChain(state); - return error; - } + if(!ActivateBestChainStep(state,pblockindex,NULL)) + { + string error=state.GetRejectReason(); + ActivateBestChain(state); + return error; + } + } + setBlockIndexCandidates.insert(pblockindex); LogPrintf("Set active chain tip: %s\n",hash.GetHex().c_str()); @@ -4046,6 +4184,34 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f } /* MCHN START */ + +bool CheckBlockForUpgardableConstraints(const CBlock& block, CValidationState& state, string parameter, bool in_sync) +{ + if(!in_sync) + { + return true; + } + + if(parameter == "maximum-block-size") + { + if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + return state.DoS(100, error("CheckBlock() : size limits failed"), + REJECT_INVALID, "bad-blk-length"); + } + if(parameter == "maximum-block-sigops") + { + unsigned int nSigOps = 0; + BOOST_FOREACH(const CTransaction& tx, block.vtx) + { + nSigOps += GetLegacySigOpCount(tx); + } + if (nSigOps > MAX_BLOCK_SIGOPS) + return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"), + REJECT_INVALID, "bad-blk-sigops", true); + } + return true; +} + //bool CheckBlock(CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot) bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot) /* MCHN END */ @@ -4078,10 +4244,16 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // because we receive the wrong transactions for it. // Size limits + if(!CheckBlockForUpgardableConstraints(block,state,"maximum-block-size",false)) + { + return false; + } +/* if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return state.DoS(100, error("CheckBlock() : size limits failed"), REJECT_INVALID, "bad-blk-length"); - +*/ + // First transaction must be coinbase, the rest must not be if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) return state.DoS(100, error("CheckBlock() : first tx is not coinbase"), @@ -4111,7 +4283,12 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo } } + if(!CheckBlockForUpgardableConstraints(block,state,"maximum-block-sigops",false)) + { + return false; + } +/* unsigned int nSigOps = 0; BOOST_FOREACH(const CTransaction& tx, block.vtx) { @@ -4120,7 +4297,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo if (nSigOps > MAX_BLOCK_SIGOPS) return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"), REJECT_INVALID, "bad-blk-sigops", true); - +*/ return true; } @@ -4152,7 +4329,7 @@ bool CheckBranchForInvalidBlocks(CBlockIndex * const pindexPrev) -bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev) +bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev, CBlockIndex *pindexChecked) { uint256 hash = block.GetHash(); if (hash == Params().HashGenesisBlock()) @@ -4225,11 +4402,14 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta } } } - - if(!CheckBranchForInvalidBlocks(pindexPrev)) + + if(pindexChecked != pindexPrev) { - return state.Invalid(error("%s : %s rejected - invalid branch", __func__,block.GetHash().ToString().c_str()), - REJECT_INVALID, "reorg-invalid branch"); + if(!CheckBranchForInvalidBlocks(pindexPrev)) + { + return state.Invalid(error("%s : %s rejected - invalid branch", __func__,block.GetHash().ToString().c_str()), + REJECT_INVALID, "reorg-invalid branch"); + } } @@ -4282,7 +4462,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn return true; } -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex, int node_id) +bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex, int node_id, CBlockIndex *pindexChecked) { AssertLockHeld(cs_main); // Check for duplicate @@ -4296,10 +4476,13 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc *ppindex = pindex; if (pindex->nStatus & BLOCK_FAILED_MASK) return state.Invalid(error("%s : block is marked invalid", __func__), 0, "duplicate"); - if(!CheckBranchForInvalidBlocks(pindex->pprev)) + if(pindexChecked != pindex->pprev) { - return state.Invalid(error("%s : %s rejected - invalid branch", __func__,block.GetHash().ToString().c_str()), - REJECT_INVALID, "reorg-invalid branch"); + if(!CheckBranchForInvalidBlocks(pindex->pprev)) + { + return state.Invalid(error("%s : %s rejected - invalid branch", __func__,block.GetHash().ToString().c_str()), + REJECT_INVALID, "reorg-invalid branch"); + } } return true; } @@ -4318,7 +4501,7 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc return state.DoS(10, error("%s : prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");// MCHN was 100 before, softened for reorgs due to mining diversity change } - if (!ContextualCheckBlockHeader(block, state, pindexPrev)) + if (!ContextualCheckBlockHeader(block, state, pindexPrev, pindexChecked)) return false; int successor=0; @@ -5099,10 +5282,12 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) static std::multimap mapBlocksUnknownParent; int64_t nStart = GetTimeMillis(); + uint32_t effective_max_block_size=GetArg("-loadblockmaxsize",2*MAX_BLOCK_SIZE); + int nLoaded = 0; try { // This takes over fileIn and calls fclose() on it in the CBufferedFile destructor - CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); + CBufferedFile blkdat(fileIn, 2*effective_max_block_size, effective_max_block_size+8, SER_DISK, CLIENT_VERSION); uint64_t nRewind = blkdat.GetPos(); while (!blkdat.eof()) { boost::this_thread::interruption_point(); @@ -6223,7 +6408,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 20); return error("non-continuous headers sequence"); } - if (!AcceptBlockHeader(header, state, &pindexLast, pfrom->GetId())) { + if (!AcceptBlockHeader(header, state, &pindexLast, pfrom->GetId(),pindexLast)) { int nDoS; if (state.IsInvalid(nDoS)) { if (nDoS > 0) diff --git a/src/core/main.h b/src/core/main.h index f5316228..9eca8043 100644 --- a/src/core/main.h +++ b/src/core/main.h @@ -58,11 +58,11 @@ static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0; /** The maximum size for transactions we're willing to relay/mine */ extern unsigned int MAX_STANDARD_TX_SIZE; // MCHN global /** The maximum allowed number of signature check operations in a block (network rule) */ -static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; +extern unsigned int MAX_BLOCK_SIGOPS; // MCHN global +/** The maximum number of sigops we're willing to relay/mine in a single tx */ +extern unsigned int MAX_TX_SIGOPS; // MCHN global /** Maximum number of signature check operations in an IsStandard() P2SH script */ static const unsigned int MAX_P2SH_SIGOPS = 15; -/** The maximum number of sigops we're willing to relay/mine in a single tx */ -static const unsigned int MAX_TX_SIGOPS = MAX_BLOCK_SIGOPS/5; /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ /* MCHN START */ //static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; @@ -73,6 +73,7 @@ static const unsigned int DEFAULT_MAX_SUCCESSORS_FROM_ONE_NODE = 10; /* MCHN END */ extern int MAX_OP_RETURN_SHOWN; extern int MAX_FORMATTED_DATA_DEPTH; +extern int MIN_BLOCKS_BETWEEN_UPGRADES; /* MCHN END */ /** The maximum size of a blk?????.dat file (since 0.8) */ extern unsigned int MAX_BLOCKFILE_SIZE; // MCHN global @@ -395,9 +396,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin /** Context-independent validity checks */ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); +bool CheckBlockForUpgardableConstraints(const CBlock& block, CValidationState& state, std::string parameter, bool in_sync); /** Context-dependent validity checks */ -bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev); +bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev, CBlockIndex *pindexChecked = NULL); bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); /** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ @@ -405,7 +407,7 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex /** Store block on disk. If dbp is provided, the file is known to already reside on disk */ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, CDiskBlockPos* dbp = NULL, int node_id = 0); -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL, int node_id = 0); +bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL, int node_id = 0, CBlockIndex *pindexChecked = NULL); diff --git a/src/custom/custom.cpp b/src/custom/custom.cpp new file mode 100644 index 00000000..c759d078 --- /dev/null +++ b/src/custom/custom.cpp @@ -0,0 +1,19 @@ +// Copyright (c) 2014-2017 Coin Sciences Ltd +// MultiChain code distributed under the GPLv3 license, see COPYING file. + +#include "custom/custom.h" + +using namespace std; + +int custom_version_info(int version) +{ + return 0; +} + +void custom_set_runtime_defaults(int exe_type) +{ + +} + + + diff --git a/src/custom/custom.h b/src/custom/custom.h new file mode 100644 index 00000000..9d134eb6 --- /dev/null +++ b/src/custom/custom.h @@ -0,0 +1,36 @@ +// Copyright (c) 2014-2017 Coin Sciences Ltd +// MultiChain code distributed under the GPLv3 license, see COPYING file. + +#include "core/main.h" +#include "utils/util.h" +#include "utils/utilparse.h" +#include "multichain/multichain.h" +#include "structs/base58.h" +#include "version/version.h" + + + +#ifndef CUSTOM_H +#define CUSTOM_H + +#ifdef __cplusplus +extern "C" { +#endif + +int custom_version_info(int version); +bool custom_good_for_coin_selection(const CScript& script); +bool custom_accept_transacton(const CTransaction& tx, + const CCoinsViewCache &inputs, + int offset, + bool accept, + std::string& reason, + uint32_t *replay); + +void custom_set_runtime_defaults(int exe_type); + +#ifdef __cplusplus +} +#endif + +#endif /* CUSTOM_H */ + diff --git a/src/custom/custom_multichain.cpp b/src/custom/custom_multichain.cpp new file mode 100644 index 00000000..b67933ce --- /dev/null +++ b/src/custom/custom_multichain.cpp @@ -0,0 +1,12 @@ +// Copyright (c) 2014-2017 Coin Sciences Ltd +// MultiChain code distributed under the GPLv3 license, see COPYING file. + +#include "multichain/multichain.h" + +void* custom_get_blockchain_default(const char *param,int* size,void *param_in) +{ + *size=0; + + return NULL; +} + diff --git a/src/custom/custom_server.cpp b/src/custom/custom_server.cpp new file mode 100644 index 00000000..7fac2277 --- /dev/null +++ b/src/custom/custom_server.cpp @@ -0,0 +1,22 @@ +// Copyright (c) 2014-2017 Coin Sciences Ltd +// MultiChain code distributed under the GPLv3 license, see COPYING file. + +#include "custom/custom.h" + +using namespace std; + +bool custom_good_for_coin_selection(const CScript& script) +{ + return true; +} + +bool custom_accept_transacton(const CTransaction& tx, + const CCoinsViewCache &inputs, + int offset, + bool accept, + string& reason, + uint32_t *replay) +{ + return true; +} + diff --git a/src/entities/asset.cpp b/src/entities/asset.cpp index e1150cfb..89b26090 100644 --- a/src/entities/asset.cpp +++ b/src/entities/asset.cpp @@ -536,7 +536,31 @@ void mc_EntityDetails::Set(mc_EntityLedgerRow* row) } m_Flags |= MC_ENT_FLAG_OFFSET_IS_SET; } - + + m_Permissions=0; + switch(m_LedgerRow.m_EntityType) + { + case MC_ENT_TYPE_ASSET: + m_Permissions |= MC_PTP_ADMIN | MC_PTP_ISSUE; + if(mc_gState->m_Features->PerAssetPermissions()) + { + m_Permissions |= MC_PTP_ACTIVATE; + } + break; + case MC_ENT_TYPE_STREAM: + m_Permissions |= MC_PTP_ADMIN | MC_PTP_ACTIVATE | MC_PTP_WRITE; + break; + default: + if(mc_gState->m_Features->FixedIn10007()) + { + if(m_LedgerRow.m_EntityType <= MC_ENT_TYPE_STREAM_MAX) + { + m_Permissions = MC_PTP_WRITE | MC_PTP_ACTIVATE; + } + } + break; + } + if(script_size) { value_offset=mc_FindSpecialParamInDetailsScript(m_LedgerRow.m_Script,m_LedgerRow.m_ScriptSize,MC_ENT_SPRM_NAME,&value_size); @@ -566,6 +590,16 @@ void mc_EntityDetails::Set(mc_EntityLedgerRow* row) mc_StringLowerCase(m_Name,value_size); m_Flags |= MC_ENT_FLAG_NAME_IS_SET; } + + value_offset=mc_FindSpecialParamInDetailsScript(m_LedgerRow.m_Script,m_LedgerRow.m_ScriptSize,MC_ENT_SPRM_PERMISSIONS,&value_size); + if(value_offset <= m_LedgerRow.m_ScriptSize) + { + if((value_size>0) && (value_size<=4)) + { + m_Permissions |= (uint32_t)mc_GetLE(m_LedgerRow.m_Script+value_offset,value_size); + } + } + } mc_ZeroABRaw(m_FullRef); @@ -641,18 +675,21 @@ int mc_AssetDB::InsertEntity(const void* txid, int offset, int entity_type, cons { if(script) { - value_offset=mc_FindSpecialParamInDetailsScript((unsigned char*)script,script_size,MC_ENT_SPRM_UPGRADE_PROTOCOL_VERSION,&value_size); - if(value_offset == script_size) - { - return MC_ERR_ERROR_IN_SCRIPT; - } - if( (value_size <=0) || (value_size > 4) ) + if(mc_gState->m_Features->ParameterUpgrades() == 0) { - return MC_ERR_ERROR_IN_SCRIPT; - } - if((int)mc_GetLE((unsigned char*)script+value_offset,value_size) < 0) - { - return MC_ERR_ERROR_IN_SCRIPT; + value_offset=mc_FindSpecialParamInDetailsScript((unsigned char*)script,script_size,MC_ENT_SPRM_UPGRADE_PROTOCOL_VERSION,&value_size); + if(value_offset == script_size) + { + return MC_ERR_ERROR_IN_SCRIPT; + } + if( (value_size <=0) || (value_size > 4) ) + { + return MC_ERR_ERROR_IN_SCRIPT; + } + if((int)mc_GetLE((unsigned char*)script+value_offset,value_size) < 0) + { + return MC_ERR_ERROR_IN_SCRIPT; + } } value_offset=mc_FindSpecialParamInDetailsScript((unsigned char*)script,script_size,MC_ENT_SPRM_UPGRADE_START_BLOCK,&value_size); if(value_offset != script_size) @@ -1585,7 +1622,24 @@ int mc_AssetDB::FindEntityByFollowOn(mc_EntityDetails *entity,const unsigned cha return 0; } - +const unsigned char* mc_EntityDetails::GetParamUpgrades(int *size) +{ + uint32_t value_offset; + size_t value_size; + + if(m_LedgerRow.m_ScriptSize) + { + value_offset=mc_FindSpecialParamInDetailsScript(m_LedgerRow.m_Script,m_LedgerRow.m_ScriptSize,MC_ENT_SPRM_UPGRADE_CHAIN_PARAMS,&value_size); + if(value_offset != m_LedgerRow.m_ScriptSize) + { + *size=(int)value_size; + return m_LedgerRow.m_Script+value_offset; + } + } + + *size=0; + return NULL; +} const char* mc_EntityDetails::GetName() { @@ -1710,6 +1764,12 @@ int mc_EntityDetails::AllowedFollowOns() return 0; } +uint32_t mc_EntityDetails::Permissions() +{ + return m_Permissions; +} + + int mc_EntityDetails::AnyoneCanWrite() { unsigned char *ptr; @@ -1744,12 +1804,17 @@ int mc_EntityDetails::UpgradeProtocolVersion() { unsigned char *ptr; size_t bytes; + int version; ptr=(unsigned char *)GetSpecialParam(MC_ENT_SPRM_UPGRADE_PROTOCOL_VERSION,&bytes); if(ptr) { if((bytes>0) && (bytes<=4)) { - return (int)mc_GetLE(ptr,bytes); + version=(int)mc_GetLE(ptr,bytes); + if(version > 0) + { + return version; + } } } return 0; diff --git a/src/entities/asset.h b/src/entities/asset.h index f92d52ee..60fa458c 100644 --- a/src/entities/asset.h +++ b/src/entities/asset.h @@ -56,9 +56,11 @@ #define MC_ENT_SPRM_ISSUER 0x03 #define MC_ENT_SPRM_ANYONE_CAN_WRITE 0x04 #define MC_ENT_SPRM_JSON_DETAILS 0x05 +#define MC_ENT_SPRM_PERMISSIONS 0x06 #define MC_ENT_SPRM_ASSET_MULTIPLE 0x41 #define MC_ENT_SPRM_UPGRADE_PROTOCOL_VERSION 0x42 #define MC_ENT_SPRM_UPGRADE_START_BLOCK 0x43 +#define MC_ENT_SPRM_UPGRADE_CHAIN_PARAMS 0x44 #define MC_ENT_FLAG_OFFSET_IS_SET 0x00000001 #define MC_ENT_FLAG_NAME_IS_SET 0x00000010 @@ -135,6 +137,7 @@ typedef struct mc_EntityDetails unsigned char m_FullRef[MC_AST_ASSET_QUANTITY_OFFSET]; // Full Entity reference, derived from short txid from v 10007 char m_Name[MC_ENT_MAX_NAME_SIZE+6]; // Entity name uint32_t m_Flags; + uint32_t m_Permissions; unsigned char m_Reserved[36]; mc_EntityLedgerRow m_LedgerRow; void Zero(); @@ -145,11 +148,14 @@ typedef struct mc_EntityDetails const unsigned char* GetFullRef(); const unsigned char* GetShortRef(); const unsigned char* GetScript(); + const unsigned char* GetParamUpgrades(int *size); + int IsUnconfirmedGenesis(); int GetAssetMultiple(); int IsFollowOn(); // int HasFollowOns(); int AllowedFollowOns(); + uint32_t Permissions(); int AnyoneCanWrite(); int UpgradeProtocolVersion(); uint32_t UpgradeStartBlock(); diff --git a/src/json/json_spirit_ubjson.cpp b/src/json/json_spirit_ubjson.cpp index 2b6f28f5..04a2f941 100644 --- a/src/json/json_spirit_ubjson.cpp +++ b/src/json/json_spirit_ubjson.cpp @@ -355,7 +355,7 @@ int ubjson_write_internal(Value json_value,int known_type,mc_Script *lpScript,in ssize=usize; } } - value=array_value.size(); + value=(int)array_value.size(); ubj_type=ubjson_best_type(value,0,NULL,NULL,NULL); if(ssize+(int64_t)array_value.size()+1 <= (int64_t)array_value.size()*UBJ_SIZE[last_type]+UBJ_SIZE[ubj_type]+4) { @@ -443,7 +443,7 @@ int ubjson_write_internal(Value json_value,int known_type,mc_Script *lpScript,in ssize=usize; } } - value=obj_value.size(); + value=(int)obj_value.size(); ubj_type=ubjson_best_type(value,0,NULL,NULL,NULL); if(ssize+(int64_t)obj_value.size()+1 <= (int64_t)obj_value.size()*UBJ_SIZE[last_type]+UBJ_SIZE[ubj_type]+4) { diff --git a/src/miner/miner.cpp b/src/miner/miner.cpp index 4f5e3948..6c0ae8a8 100644 --- a/src/miner/miner.cpp +++ b/src/miner/miner.cpp @@ -261,7 +261,7 @@ bool CreateBlockSignature(CBlock *block,uint32_t hash_type,CWallet *pwallet) /* MCHN START */ //CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,CWallet *pwallet,CPubKey *ppubkey,int *canMine) +CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,CWallet *pwallet,CPubKey *ppubkey,int *canMine,CBlockIndex** ppPrev) /* MCHN END */ { // Create new block @@ -322,6 +322,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,CWallet *pwallet,CP CBlockIndex* pindexPrev = chainActive.Tip(); const int nHeight = pindexPrev->nHeight + 1; + if(ppPrev) + { + *ppPrev=pindexPrev; + } CCoinsViewCache view(pcoinsTip); // Priority order to process transactions @@ -469,7 +473,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,CWallet *pwallet,CP // Collect transactions into block uint64_t nBlockSize = 1000; uint64_t nBlockTx = 0; - int nBlockSigOps = 100; + int nBlockSigOps = 40; // bool fSortedByFee = (nBlockPrioritySize <= 0); /* MCHN START */ @@ -678,7 +682,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,CWallet *pwallet,CP /* MCHN START */ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { - return CreateNewBlock(scriptPubKeyIn,NULL,NULL,NULL); + return CreateNewBlock(scriptPubKeyIn,NULL,NULL,NULL,NULL); } /* MCHN END */ @@ -769,7 +773,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) // Block should be mined for specific keys, not just any from pool -CBlockTemplate* CreateNewBlockWithDefaultKey(CWallet *pwallet,int *canMine,const set* addresses) +CBlockTemplate* CreateNewBlockWithDefaultKey(CWallet *pwallet,int *canMine,const set* addresses,CBlockIndex** ppPrev) { CPubKey pubkey; bool key_found; @@ -795,7 +799,7 @@ CBlockTemplate* CreateNewBlockWithDefaultKey(CWallet *pwallet,int *canMine,const CScript scriptPubKey = CScript() << OP_DUP << OP_HASH160 << vector(pubkey_hash, pubkey_hash + 20) << OP_EQUALVERIFY << OP_CHECKSIG; - return CreateNewBlock(scriptPubKey,pwallet,&pubkey,canMine); + return CreateNewBlock(scriptPubKey,pwallet,&pubkey,canMine,ppPrev); } /* MCHN END */ @@ -1422,7 +1426,7 @@ void static BitcoinMiner(CWallet *pwallet) const unsigned char *pubkey_hash=(unsigned char *)Hash160(kMiner.begin(),kMiner.end()).begin(); CScript scriptPubKey = CScript() << OP_DUP << OP_HASH160 << vector(pubkey_hash, pubkey_hash + 20) << OP_EQUALVERIFY << OP_CHECKSIG; canMine=prevCanMine; - auto_ptr pblocktemplate(CreateNewBlock(scriptPubKey,pwallet,&kMiner,&canMine)); + auto_ptr pblocktemplate(CreateNewBlock(scriptPubKey,pwallet,&kMiner,&canMine,&pindexPrev)); prevCanMine=canMine; /* MCHN END */ if (!pblocktemplate.get()) diff --git a/src/miner/miner.h b/src/miner/miner.h index abe4db1a..fff4a3bd 100644 --- a/src/miner/miner.h +++ b/src/miner/miner.h @@ -27,7 +27,7 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads); /** Generate a new block, without valid proof-of-work */ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey); -CBlockTemplate* CreateNewBlockWithDefaultKey(CWallet *pwallet,int *canMine, const std::set* addresses = NULL); +CBlockTemplate* CreateNewBlockWithDefaultKey(CWallet *pwallet,int *canMine, const std::set* addresses = NULL,CBlockIndex** ppPrev = NULL); /** Modify the extranonce in a block */ /* MCHN START */ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce,CWallet *pwallet); diff --git a/src/multichain/multichain-cli.cpp b/src/multichain/multichain-cli.cpp index a975b491..22b0fb19 100644 --- a/src/multichain/multichain-cli.cpp +++ b/src/multichain/multichain-cli.cpp @@ -36,7 +36,7 @@ std::string HelpMessageCli() strUsage += " -? " + _("This help message") + "\n"; strUsage += " -conf= " + strprintf(_("Specify configuration file (default: %s)"), "multichain.conf") + "\n"; strUsage += " -datadir= " + _("Specify data directory") + "\n"; - strUsage += " -cold= " + _("Connect to multichaind-cold: use multichaind-cold default directory if -datadir is not set") + "\n"; + strUsage += " -cold " + _("Connect to multichaind-cold: use multichaind-cold default directory if -datadir is not set") + "\n"; /* MCHN START */ strUsage += " -requestout= " + _("Send request to stderr, stdout or null (not print it at all), default stderr") + "\n"; strUsage += " -saveclilog= " + _("If =0 multichain-cli history is not saved, default 1") + "\n"; diff --git a/src/multichain/multichaind-cold.cpp b/src/multichain/multichaind-cold.cpp index 3df8ae19..cc3a01ee 100644 --- a/src/multichain/multichaind-cold.cpp +++ b/src/multichain/multichaind-cold.cpp @@ -147,7 +147,7 @@ bool AppInit(int argc, char* argv[]) if(!GetBoolArg("-shortoutput", false)) { - fprintf(stdout, "MultiChain server starting\n"); + fprintf(stdout, "Starting up node...\n"); } if (pipe(pipes)) diff --git a/src/multichain/multichaind.cpp b/src/multichain/multichaind.cpp index 9285d77f..93d63b49 100644 --- a/src/multichain/multichaind.cpp +++ b/src/multichain/multichaind.cpp @@ -142,7 +142,7 @@ bool AppInit(int argc, char* argv[]) if(!GetBoolArg("-shortoutput", false)) { - fprintf(stdout, "MultiChain server starting\n"); + fprintf(stdout, "Starting up node...\n\n"); } if (pipe(pipes)) diff --git a/src/permissions/permission.cpp b/src/permissions/permission.cpp index ac7435d0..3c36752a 100644 --- a/src/permissions/permission.cpp +++ b/src/permissions/permission.cpp @@ -710,6 +710,29 @@ int mc_MemcmpCheckSize(const void *s1,const char *s2,size_t s1_size) return memcmp(s1,s2,s1_size); } +uint32_t mc_Permissions::GetPossiblePermissionTypes(const void* entity_details) +{ + uint32_t full_type; + mc_EntityDetails *entity; + entity=(mc_EntityDetails *)entity_details; + + if(entity) + { + if(entity->GetEntityType()) + { + return entity->Permissions(); + } + } + + full_type = MC_PTP_GLOBAL_ALL; + if(mc_gState->m_Features->Streams() == 0) + { + full_type-=MC_PTP_CREATE; + } + + return full_type; +} + uint32_t mc_Permissions::GetPossiblePermissionTypes(uint32_t entity_type) { uint32_t full_type; @@ -746,15 +769,20 @@ uint32_t mc_Permissions::GetPossiblePermissionTypes(uint32_t entity_type) /** Return ORed MC_PTP_ constants by textual value */ -uint32_t mc_Permissions::GetPermissionType(const char *str,int entity_type) +uint32_t mc_Permissions::GetPermissionType(const char *str,const void* entity_details) +{ + return GetPermissionType(str,GetPossiblePermissionTypes(entity_details)); +} + +uint32_t mc_Permissions::GetPermissionType(const char *str,uint32_t full_type) { - uint32_t result,perm_type,full_type; + uint32_t result,perm_type; char* ptr; char* start; char* ptrEnd; char c; - full_type=GetPossiblePermissionTypes(entity_type); +// full_type=GetPossiblePermissionTypes(entity_details); ptr=(char*)str; ptrEnd=ptr+strlen(ptr); @@ -3019,7 +3047,7 @@ int mc_Permissions::SetPermissionInternal(const void* lpEntity,const void* lpAdd mc_PermissionLedgerRow pldLast; int err,i,num_types,thisBlock,lastAllowed,thisAllowed; char msg[256]; - uint32_t types[9]; + uint32_t types[32]; uint32_t pr_entity,pr_address,pr_admin; num_types=0; types[num_types]=MC_PTP_CONNECT;num_types++; diff --git a/src/permissions/permission.h b/src/permissions/permission.h index e8a09a45..61d39fb8 100644 --- a/src/permissions/permission.h +++ b/src/permissions/permission.h @@ -290,8 +290,11 @@ typedef struct mc_Permissions int RollBackToCheckPoint(); uint32_t GetAllPermissions(const void* lpEntity,const void* lpAddress,uint32_t type); - uint32_t GetPermissionType(const char *str,int entity_type); + uint32_t GetPermissionType(const char *str,uint32_t full_type); +// uint32_t GetPermissionType(const char *str,int entity_type); + uint32_t GetPermissionType(const char *str,const void *entity_details); uint32_t GetPossiblePermissionTypes(uint32_t entity_type); + uint32_t GetPossiblePermissionTypes(const void *entity_details); int GetAdminCount(); int GetMinerCount(); diff --git a/src/protocol/multichainblock.cpp b/src/protocol/multichainblock.cpp index d5ec0fd1..90f11268 100644 --- a/src/protocol/multichainblock.cpp +++ b/src/protocol/multichainblock.cpp @@ -9,6 +9,8 @@ #include "multichain/multichain.h" #include "wallet/wallettxs.h" +#include + extern mc_WalletTxs* pwalletTxsMain; @@ -31,6 +33,284 @@ bool AcceptPermissionsAndCheckForDust(const CTransaction &tx,bool accept,string& bool IsTxBanned(uint256 txid); +int CreateUpgradeLists(int current_height,vector *vParams,vector *vUpgrades) +{ + mc_EntityDetails entity; + mc_Buffer *upgrades; + mc_UpgradeStatus upgrade; + mc_UpgradedParameter param; + + upgrades=NULL; + set stored_upgrades; + map map_sorted; + map map_last_upgrade; + uint160 hash=0; + + int OriginalProtocolVersion=(int)mc_gState->m_NetworkParams->GetInt64Param("protocolversion"); + int NewProtocolVersion=OriginalProtocolVersion; + int version; + int err=MC_ERR_NOERROR; + + if(vUpgrades) + { + vUpgrades->clear(); + } + vParams->clear(); + + upgrades=mc_gState->m_Permissions->GetUpgradeList(NULL,NULL); + + + for(int i=0;iGetCount();i++) + { + mc_PermissionDetails *plsRow; + plsRow=(mc_PermissionDetails *)(upgrades->GetRow(i)); + if(plsRow->m_Type == MC_PTP_UPGRADE) + { + if(vParams) + { + memcpy(&hash,plsRow->m_Address,sizeof(uint160)); + stored_upgrades.insert(hash); + } + map_sorted.insert(std::make_pair(plsRow->m_LastRow,i)); + } + } + + if(vParams) + { + for(int i=0;iGetCount();i++) + { + mc_PermissionDetails *plsRow; + plsRow=(mc_PermissionDetails *)(upgrades->GetRow(i)); + if(plsRow->m_Type != MC_PTP_UPGRADE) + { + memcpy(&hash,plsRow->m_Address,sizeof(uint160)); + if(stored_upgrades.count(hash) == 0) + { + plsRow->m_BlockTo = 0; + map_sorted.insert(std::make_pair(plsRow->m_LastRow,i)); + } + } + } + } + +/* + for(int i=0;iGetCount();i++) + { + mc_PermissionDetails *plsRow; + plsRow=(mc_PermissionDetails *)(permissions->GetRow(i)); + if(plsRow->m_Type == MC_PTP_UPGRADE) + { + map_sorted.insert(std::make_pair(plsRow->m_LastRow,i)); + } + } +*/ + BOOST_FOREACH(PAIRTYPE(const uint64_t, int)& item, map_sorted) + { + int i=item.second; + mc_PermissionDetails *plsRow; + plsRow=(mc_PermissionDetails *)(upgrades->GetRow(i)); +// if(plsRow->m_Type == MC_PTP_UPGRADE) + if(err == MC_ERR_NOERROR) + { + memset(&upgrade,0,sizeof(mc_UpgradeStatus)); + memcpy(upgrade.m_EntityShortTxID,plsRow->m_Address,MC_AST_SHORT_TXID_SIZE); + upgrade.m_ApprovedBlock=current_height+2; + upgrade.m_AppliedBlock=current_height+2; + upgrade.m_FirstParam=(int)vParams->size(); + if(plsRow->m_BlockFrom < plsRow->m_BlockTo) + { + upgrade.m_ApprovedBlock=plsRow->m_BlockReceived; + if(mc_gState->m_Assets->FindEntityByShortTxID(&entity,plsRow->m_Address)) + { + int applied_height=entity.UpgradeStartBlock(); + if((int)plsRow->m_BlockReceived > applied_height) + { + applied_height=plsRow->m_BlockReceived; + } + upgrade.m_AppliedBlock=applied_height; + if(current_height >= applied_height) + { + version=entity.UpgradeProtocolVersion(); + if(version > 0) + { + param.m_Param=mc_gState->m_NetworkParams->FindParam("protocolversion"); + param.m_Value=version; + param.m_Block=upgrade.m_AppliedBlock; + param.m_Skipped=MC_PSK_APPLIED; + if(version >= mc_gState->MinProtocolDowngradeVersion()) + { + if((NewProtocolVersion < mc_gState->MinProtocolForbiddenDowngradeVersion()) || (version >= NewProtocolVersion)) + { + NewProtocolVersion=version; + if( mc_gState->IsSupported(version) == 0 ) + { + err=MC_ERR_NOT_SUPPORTED; + } + } + else + { + param.m_Skipped = MC_PSK_OLD_NOT_DOWNGRADABLE; + } + } + else + { + param.m_Skipped = MC_PSK_NEW_NOT_DOWNGRADABLE; + } + vParams->push_back(param); + } + + if(err == MC_ERR_NOERROR) + { + int size=0; + char* ptr=(char*)entity.GetParamUpgrades(&size); + char* ptrEnd; + int param_size,given_size; + int64_t param_value; + if(ptr) + { + ptrEnd=ptr+size; + while(ptrm_NetworkParams->FindParam(ptr); + ptr+=mc_gState->m_NetworkParams->GetParamFromScript(ptr,¶m_value,&given_size); + param.m_Value=param_value; + param.m_Block=upgrade.m_AppliedBlock; + param.m_Skipped=MC_PSK_APPLIED; + if(param.m_Param) + { + param_size=mc_gState->m_NetworkParams->CanBeUpgradedByVersion(param.m_Param->m_Name,NewProtocolVersion,0); + if( (param_size > 0) && (param_size == given_size) ) + { + if(mc_gState->m_NetworkParams->IsParamUpgradeValueInRange(param.m_Param,NewProtocolVersion,param_value)) + { + bool take_it=true; + string param_name=string(param.m_Param->m_Name); + map ::iterator it = map_last_upgrade.find(param_name); + + if (it != map_last_upgrade.end()) + { + take_it=false; + if( ( (param.m_Param->m_Type & MC_PRM_TIME) == 0 ) || + ((*vParams)[it->second].m_Block + MIN_BLOCKS_BETWEEN_UPGRADES <= upgrade.m_AppliedBlock) ) + { + int64_t old_value=(*vParams)[it->second].m_Value; + if(param.m_Value >= old_value) + { + if(param_value <= 2*old_value) + { + take_it=true; + } + } + else + { + if(old_value <= 2*param_value) + { + take_it=true; + } + } + if(!take_it) + { + param.m_Skipped =MC_PSK_DOUBLE_RANGE; + } + } + else + { + param.m_Skipped = MC_PSK_FRESH_UPGRADE; + } + if(take_it) + { + it->second=(int)vParams->size(); + } + } + else + { + take_it=false; + int64_t old_value=mc_gState->m_NetworkParams->GetInt64Param(param.m_Param->m_Name); + + if(param.m_Value >= old_value) + { + if(param_value <= 2*old_value) + { + take_it=true; + } + } + else + { + if(old_value <= 2*param_value) + { + take_it=true; + } + } + if(!take_it) + { + param.m_Skipped =MC_PSK_DOUBLE_RANGE; + } + else + { + map_last_upgrade.insert(std::make_pair(param_name,(int)vParams->size())); + } + } + } + else + { + param.m_Skipped = MC_PSK_OUT_OF_RANGE; + } + } + else + { + if(param_size > 0) + { + param.m_Skipped = MC_PSK_WRONG_SIZE; + } + else + { + if(param_size < 0) + { + param.m_Skipped = -param_size; + } + else + { + param.m_Skipped = MC_PSK_NOT_SUPPORTED; + } + } + } + if(vUpgrades == NULL) // Called from MultichainNode_ApplyUpgrades + { + if((int)param.m_Block == current_height) + { + if(param.m_Skipped == MC_PSK_APPLIED) + { + LogPrintf("PARAMETER UPGRADE: %s = %ld\n",param.m_Param->m_DisplayName,param.m_Value); + } + } + } + vParams->push_back(param); + } + else + { + param.m_Skipped = MC_PSK_NOT_FOUND; + } + } + } + } + } + } + } + upgrade.m_LastParam=(int)vParams->size(); + if(vUpgrades) + { + vUpgrades->push_back(upgrade); + } + } + } + + + mc_gState->m_Permissions->FreePermissionList(upgrades); + mc_gState->m_ProtocolVersionToUpgrade=NewProtocolVersion; + + return err; +} + bool ReplayMemPool(CTxMemPool& pool, int from,bool accept) { int pos; diff --git a/src/protocol/multichainscript.cpp b/src/protocol/multichainscript.cpp index 74429a1b..c0f5b87f 100644 --- a/src/protocol/multichainscript.cpp +++ b/src/protocol/multichainscript.cpp @@ -2214,6 +2214,83 @@ int mc_Script::SetCachedScript(int offset, int *next_offset, int vin, unsigned c return MC_ERR_NOERROR; } +int mc_Script::GetRawData(unsigned char **data,int *size) +{ + unsigned char *ptr; + unsigned char *ptrEnd; + + if(data) + { + *data=NULL; + } + + if(m_CurrentElement<0) + { + return MC_ERR_INVALID_PARAMETER_VALUE; + } + + if(m_lpCoord[m_CurrentElement*2+1] < MC_DCT_SCRIPT_IDENTIFIER_LEN+1+1) + { + return MC_ERR_WRONG_SCRIPT; + } + + ptr=m_lpData+m_lpCoord[m_CurrentElement*2+0]; + ptrEnd=ptr+m_lpCoord[m_CurrentElement*2+1]; + + if(memcmp(ptr,MC_DCT_SCRIPT_MULTICHAIN_IDENTIFIER,MC_DCT_SCRIPT_IDENTIFIER_LEN) != 0) + { + return MC_ERR_WRONG_SCRIPT; + } + + + if(ptr[MC_DCT_SCRIPT_IDENTIFIER_LEN] != MC_DCT_SCRIPT_MULTICHAIN_RAW_DATA_PREFIX) + { + return MC_ERR_WRONG_SCRIPT; + } + + ptr+=MC_DCT_SCRIPT_IDENTIFIER_LEN+1; + + if(data) + { + *data=ptr; + *size=ptrEnd-ptr; + } + + return MC_ERR_NOERROR; +} + +int mc_Script::SetRawData(const unsigned char *data,const int size) +{ + int err; + unsigned char buf[MC_DCT_SCRIPT_IDENTIFIER_LEN+1]; + + err=AddElement(); + if(err) + { + return err; + } + + memcpy(buf,MC_DCT_SCRIPT_MULTICHAIN_IDENTIFIER,MC_DCT_SCRIPT_IDENTIFIER_LEN); + buf[MC_DCT_SCRIPT_IDENTIFIER_LEN]=MC_DCT_SCRIPT_MULTICHAIN_RAW_DATA_PREFIX; + + err=SetData(buf,MC_DCT_SCRIPT_IDENTIFIER_LEN+1); + if(err) + { + return err; + } + + if(size) + { + err=SetData(data,size); + if(err) + { + return err; + } + } + + return MC_ERR_NOERROR; +} + int mc_Script::GetDataFormat(uint32_t *format) { unsigned char *ptr; diff --git a/src/protocol/multichainscript.h b/src/protocol/multichainscript.h index b9d09d07..1d651e0b 100644 --- a/src/protocol/multichainscript.h +++ b/src/protocol/multichainscript.h @@ -99,6 +99,9 @@ typedef struct mc_Script int GetCachedScript(int offset, int *next_offset, int* vin, unsigned char** script, int *script_size); int SetCachedScript(int offset, int *next_offset, int vin, unsigned char* script, int script_size); + int GetRawData(unsigned char **data,int *size); + int SetRawData(const unsigned char *data,const int size); + int GetDataFormat(uint32_t *format); int SetDataFormat(const uint32_t format); diff --git a/src/protocol/multichaintx.cpp b/src/protocol/multichaintx.cpp index 94157bf9..23b24c74 100644 --- a/src/protocol/multichaintx.cpp +++ b/src/protocol/multichaintx.cpp @@ -6,8 +6,10 @@ #include "core/main.h" #include "utils/util.h" +#include "utils/utilparse.h" #include "multichain/multichain.h" #include "structs/base58.h" +#include "custom/custom.h" using namespace std; @@ -47,7 +49,9 @@ uint160 mc_GenesisAdmin(const CTransaction& tx) return 0; } -bool mc_ExtractInputAssetQuantities(const CScript& script1, uint256 hash, string& reason) + + +bool mc_ExtractInputAssetQuantities(mc_Buffer *assets, const CScript& script1, uint256 hash, string& reason) { int err; int64_t quantity; @@ -59,7 +63,7 @@ bool mc_ExtractInputAssetQuantities(const CScript& script1, uint256 hash, string for (int e = 0; e < mc_gState->m_TmpScript->GetNumElements(); e++) { mc_gState->m_TmpScript->SetElement(e); - err=mc_gState->m_TmpScript->GetAssetQuantities(mc_gState->m_TmpAssetsIn,MC_SCR_ASSET_SCRIPT_TYPE_TRANSFER | MC_SCR_ASSET_SCRIPT_TYPE_FOLLOWON); + err=mc_gState->m_TmpScript->GetAssetQuantities(assets,MC_SCR_ASSET_SCRIPT_TYPE_TRANSFER | MC_SCR_ASSET_SCRIPT_TYPE_FOLLOWON); if((err != MC_ERR_NOERROR) && (err != MC_ERR_WRONG_SCRIPT)) { reason="Asset transfer script rejected - error in script"; @@ -82,17 +86,17 @@ bool mc_ExtractInputAssetQuantities(const CScript& script1, uint256 hash, string } } memcpy(buf_amounts,entity.GetFullRef(),MC_AST_ASSET_FULLREF_SIZE); - int row=mc_gState->m_TmpAssetsIn->Seek(buf_amounts); + int row=assets->Seek(buf_amounts); if(row>=0) { - int64_t last=mc_GetABQuantity(mc_gState->m_TmpAssetsIn->GetRow(row)); + int64_t last=mc_GetABQuantity(assets->GetRow(row)); quantity+=last; - mc_SetABQuantity(mc_gState->m_TmpAssetsIn->GetRow(row),quantity); + mc_SetABQuantity(assets->GetRow(row),quantity); } else { mc_SetABQuantity(buf_amounts,quantity); - mc_gState->m_TmpAssetsIn->Add(buf_amounts); + assets->Add(buf_amounts); } } else @@ -114,22 +118,6 @@ bool mc_ExtractInputAssetQuantities(const CScript& script1, uint256 hash, string return true; } -bool mc_ExtractOutputAssetQuantities(string& reason) -{ - int err; - for (int e = 0; e < mc_gState->m_TmpScript->GetNumElements(); e++) - { - mc_gState->m_TmpScript->SetElement(e); - err=mc_gState->m_TmpScript->GetAssetQuantities(mc_gState->m_TmpAssetsOut,MC_SCR_ASSET_SCRIPT_TYPE_TRANSFER); - if((err != MC_ERR_NOERROR) && (err != MC_ERR_WRONG_SCRIPT)) - { - reason="Asset transfer script rejected - error in output transfer script"; - return false; - } - } - - return true; -} bool mc_CompareAssetQuantities(string& reason) { @@ -218,7 +206,7 @@ bool AcceptAssetGenesisFromPredefinedIssuers(const CTransaction &tx, int err; int64_t quantity,total; uint256 txid; - bool new_issue,follow_on; + bool new_issue,follow_on,issue_in_output; int details_script_type; unsigned char *ptrOut; vector issuers; @@ -376,12 +364,16 @@ bool AcceptAssetGenesisFromPredefinedIssuers(const CTransaction &tx, } else { + mc_gState->m_TmpAssetsTmp->Clear(); + issue_in_output=false; + for (int e = 0; e < mc_gState->m_TmpScript->GetNumElements(); e++) { mc_gState->m_TmpScript->SetElement(e); err=mc_gState->m_TmpScript->GetAssetGenesis(&quantity); if(err == 0) { + issue_in_output=true; new_issue=true; if(quantity+total<0) { @@ -427,6 +419,16 @@ bool AcceptAssetGenesisFromPredefinedIssuers(const CTransaction &tx, reason="Asset issue script rejected - error in script"; return false; } + if(mc_gState->m_Features->PerAssetPermissions()) + { + err=mc_gState->m_TmpScript->GetAssetQuantities(mc_gState->m_TmpAssetsTmp,MC_SCR_ASSET_SCRIPT_TYPE_TRANSFER); + if((err != MC_ERR_NOERROR) && (err != MC_ERR_WRONG_SCRIPT)) + { + reason="Script rejected - error in asset transfer script"; + return false; + } + } + err=mc_gState->m_TmpScript->GetAssetQuantities(mc_gState->m_TmpAssetsOut,MC_SCR_ASSET_SCRIPT_TYPE_FOLLOWON); if((err != MC_ERR_NOERROR) && (err != MC_ERR_WRONG_SCRIPT)) { @@ -443,6 +445,17 @@ bool AcceptAssetGenesisFromPredefinedIssuers(const CTransaction &tx, } } } + if(issue_in_output) + { + if(mc_gState->m_Features->PerAssetPermissions()) + { + if(mc_gState->m_TmpAssetsTmp->GetCount()) + { + reason="Asset issue script rejected - asset transfer in script"; + return false; + } + } + } } } @@ -651,6 +664,12 @@ bool AcceptAssetGenesisFromPredefinedIssuers(const CTransaction &tx, (unsigned char*)issuers[0].begin(),0,(uint32_t)(-1),timestamp,flags | MC_PFL_ENTITY_GENESIS ,update_mempool,offset); } + uint32_t all_permissions=MC_PTP_ADMIN | MC_PTP_ISSUE; + if(mc_gState->m_Features->PerAssetPermissions()) + { + all_permissions |= MC_PTP_ACTIVATE | MC_PTP_SEND | MC_PTP_RECEIVE; + } + for (unsigned int i = 0; i < issuers.size(); i++) { if(err == MC_ERR_NOERROR) @@ -664,8 +683,8 @@ bool AcceptAssetGenesisFromPredefinedIssuers(const CTransaction &tx, mc_gState->m_TmpScript->SetSpecialParamValue(MC_ENT_SPRM_ISSUER,issuer_buf,sizeof(issuer_buf)); } if(new_issue) - { - err=mc_gState->m_Permissions->SetPermission(&txid,issuer_buf,MC_PTP_ADMIN | MC_PTP_ISSUE, + { + err=mc_gState->m_Permissions->SetPermission(&txid,issuer_buf,all_permissions, (unsigned char*)issuers[0].begin(),0,(uint32_t)(-1),timestamp,flags | MC_PFL_ENTITY_GENESIS ,update_mempool,offset); } stored_issuers.insert(issuers[i]); @@ -938,10 +957,23 @@ bool AcceptMultiChainTransaction(const CTransaction& tx, vInputHashTypes.push_back(sighash_type); - if(!mc_ExtractInputAssetQuantities(script1,prevout.hash,reason)) // Filling input asset quantity list + if(mc_gState->m_Features->PerAssetPermissions()) { - return false; + mc_gState->m_TmpAssetsTmp->Clear(); + if(!mc_ExtractInputAssetQuantities(mc_gState->m_TmpAssetsTmp,script1,prevout.hash,reason)) // Filling input asset quantity list + { + return false; + } + if(!mc_VerifyAssetPermissions(mc_gState->m_TmpAssetsTmp,addressRets,1,MC_PTP_SEND,reason)) + { + return false; + } } + + if(!mc_ExtractInputAssetQuantities(mc_gState->m_TmpAssetsIn,script1,prevout.hash,reason)) + { + return false; + } } vInputCanGrantAdminMine.push_back(!fCheckCachedScript); @@ -1668,7 +1700,20 @@ bool AcceptMultiChainTransaction(const CTransaction& tx, if(pass == 3) { - if(!mc_ExtractOutputAssetQuantities(reason)) // Filling output asset quantity list + if(mc_gState->m_Features->PerAssetPermissions()) + { + mc_gState->m_TmpAssetsTmp->Clear(); + if(!mc_ExtractOutputAssetQuantities(mc_gState->m_TmpAssetsTmp,reason,true)) + { + fReject=true; + goto exitlbl; + } + if(!mc_VerifyAssetPermissions(mc_gState->m_TmpAssetsTmp,addressRets,receive_required,MC_PTP_RECEIVE,reason)) + { + return false; + } + } + if(!mc_ExtractOutputAssetQuantities(mc_gState->m_TmpAssetsOut,reason,false)) // Filling output asset quantity list { fReject=true; goto exitlbl; @@ -1896,6 +1941,7 @@ bool AcceptMultiChainTransaction(const CTransaction& tx, } } + fReject=!custom_accept_transacton(tx,inputs,offset,accept,reason,replay); exitlbl: diff --git a/src/rpc/rpcassets.cpp b/src/rpc/rpcassets.cpp index 1d928f9b..52721c19 100644 --- a/src/rpc/rpcassets.cpp +++ b/src/rpc/rpcassets.cpp @@ -60,8 +60,8 @@ Value issuefromcmd(const Array& params, bool fHelp) // Wallet comments CWalletTx wtx; - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); int64_t quantity; int multiple; @@ -123,17 +123,16 @@ Value issuefromcmd(const Array& params, bool fHelp) lpScript->SetAssetGenesis(quantity); - mc_Script *lpDetailsScript; - lpDetailsScript=NULL; - - mc_Script *lpDetails; - lpDetails=new mc_Script; - lpDetails->AddElement(); + mc_Script *lpDetailsScript=mc_gState->m_TmpBuffers->m_RpcScript1; + lpDetailsScript->Clear(); + mc_Script *lpDetails=mc_gState->m_TmpBuffers->m_RpcScript2; + lpDetails->Clear(); int ret,type; string asset_name=""; bool is_open=false; bool name_is_found=false; + uint32_t permissions=0; if (params.size() > 2 && params[2].type() != null_type)// && !params[2].get_str().empty()) { @@ -161,6 +160,24 @@ Value issuefromcmd(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid value for 'open' field, should be boolean"); } } + if(s.name_ == "restrict") + { + if(mc_gState->m_Features->PerAssetPermissions() == 0) + { + throw JSONRPCError(RPC_NOT_SUPPORTED, "Per-asset permissions not supported for this protocol version"); + } + if(permissions == 0) + { + if(s.value_.type() == str_type) + { + permissions=mc_gState->m_Permissions->GetPermissionType(s.value_.get_str().c_str(),MC_PTP_SEND | MC_PTP_RECEIVE); + if(permissions == 0) + { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid value for restrict field"); + } + } + } + } } } else @@ -202,6 +219,9 @@ Value issuefromcmd(const Array& params, bool fHelp) } } + lpDetails->Clear(); + lpDetails->AddElement(); + if(mc_gState->m_Features->OpDropDetailsScripts()) { if(asset_name.size()) @@ -217,6 +237,11 @@ Value issuefromcmd(const Array& params, bool fHelp) lpDetails->SetSpecialParamValue(MC_ENT_SPRM_FOLLOW_ONS,&b,1); } + if(permissions) + { + lpDetails->SetSpecialParamValue(MC_ENT_SPRM_PERMISSIONS,(unsigned char*)&permissions,1); + } + /* if (params.size() > 6) { @@ -247,7 +272,7 @@ Value issuefromcmd(const Array& params, bool fHelp) vector fromaddresses; int errorCode=RPC_INVALID_PARAMETER; string strError; - lpDetailsScript=new mc_Script; + lpDetailsScript->Clear(); if (params.size() > 6) { ParseRawDetails(&(params[6]),lpDetails,lpDetailsScript,&errorCode,&strError); @@ -349,13 +374,6 @@ Value issuefromcmd(const Array& params, bool fHelp) exitlbl: - if(lpDetailsScript) - { - delete lpDetailsScript; - } - delete lpDetails; - delete lpScript; - if(strError.size()) { throw JSONRPCError(errorCode, strError); @@ -399,8 +417,8 @@ Value issuemorefromcmd(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); } - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); unsigned char buf[MC_AST_ASSET_FULLREF_BUF_SIZE]; memset(buf,0,MC_AST_ASSET_FULLREF_BUF_SIZE); int multiple=1; @@ -434,19 +452,13 @@ Value issuemorefromcmd(const Array& params, bool fHelp) mc_SetABQuantity(buf,quantity); - mc_Buffer *lpBuffer; - lpBuffer=new mc_Buffer; - - mc_InitABufferDefault(lpBuffer); + mc_Buffer *lpBuffer=mc_gState->m_TmpBuffers->m_RpcABNoMapBuffer2; + lpBuffer->Clear(); lpBuffer->Add(buf); lpScript->SetAssetQuantities(lpBuffer,MC_SCR_ASSET_SCRIPT_TYPE_FOLLOWON); - delete lpBuffer; - - - // Wallet comments CWalletTx wtx; @@ -458,11 +470,12 @@ Value issuemorefromcmd(const Array& params, bool fHelp) } - mc_Script *lpDetailsScript; - lpDetailsScript=NULL; + mc_Script *lpDetailsScript=mc_gState->m_TmpBuffers->m_RpcScript1; + lpDetailsScript->Clear(); + + mc_Script *lpDetails=mc_gState->m_TmpBuffers->m_RpcScript2; + lpDetails->Clear(); - mc_Script *lpDetails; - lpDetails=new mc_Script; lpDetails->AddElement(); vector addresses; @@ -470,7 +483,6 @@ Value issuemorefromcmd(const Array& params, bool fHelp) CScript scriptOpReturn=CScript(); int errorCode=RPC_INVALID_PARAMETER; string strError; - lpDetailsScript=new mc_Script; if (params.size() > 5) { ParseRawDetails(&(params[5]),lpDetails,lpDetailsScript,&errorCode,&strError); @@ -642,13 +654,6 @@ Value issuemorefromcmd(const Array& params, bool fHelp) exitlbl: - if(lpDetailsScript) - { - delete lpDetailsScript; - } - delete lpDetails; - delete lpScript; - if(strError.size()) { throw JSONRPCError(errorCode, strError); @@ -713,6 +718,10 @@ Value getmultibalances(const Array& params, bool fHelp) set setAddresses; set setAddressesWithBalances; + set setAddressUints; + set *lpSetAddressUint=NULL; + CTxDestination dest; + if(params.size() > 0) { if( (params[0].type() != str_type) || (params[0].get_str() != "*") ) @@ -724,6 +733,30 @@ Value getmultibalances(const Array& params, bool fHelp) { return balances; } + + BOOST_FOREACH(string str_addr, setAddresses) + { + CBitcoinAddress address(str_addr); + dest=address.Get(); + const CKeyID *lpKeyID=boost::get (&dest); + const CScriptID *lpScriptID=boost::get (&dest); + if(lpKeyID) + { + setAddressUints.insert(*(uint160*)lpKeyID); + } + else + { + if(lpScriptID) + { + setAddressUints.insert(*(uint160*)lpScriptID); + } + } + } + + if(setAddressUints.size()) + { + lpSetAddressUint=&setAddressUints; + } } } @@ -765,8 +798,10 @@ Value getmultibalances(const Array& params, bool fHelp) } } - mc_Buffer *asset_amounts; - mc_Buffer *addresstxid_amounts; + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; + asset_amounts->Clear(); + mc_Buffer *addresstxid_amounts=mc_gState->m_TmpBuffers->m_RpcBuffer1; + addresstxid_amounts->Clear(); unsigned char buf[80+MC_AST_ASSET_QUANTITY_SIZE]; unsigned char totbuf[80+MC_AST_ASSET_QUANTITY_SIZE]; int64_t quantity; @@ -779,14 +814,11 @@ Value getmultibalances(const Array& params, bool fHelp) { LOCK(cs_main); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); asset_amounts->Clear(); - addresstxid_amounts=new mc_Buffer; addresstxid_amounts->Initialize(80,80+MC_AST_ASSET_QUANTITY_SIZE,MC_BUF_MODE_MAP); addresstxid_amounts->Clear(); @@ -795,7 +827,7 @@ Value getmultibalances(const Array& params, bool fHelp) vector vecOutputs; - pwalletMain->AvailableCoins(vecOutputs, false, NULL, fUnlockedOnly,true); + pwalletMain->AvailableCoins(vecOutputs, false, NULL, fUnlockedOnly,true, 0, lpSetAddressUint); BOOST_FOREACH(const COutput& out, vecOutputs) { if(!out.IsTrustedNoDepth()) @@ -1039,9 +1071,6 @@ Value getmultibalances(const Array& params, bool fHelp) } - delete addresstxid_amounts; - delete asset_amounts; - delete lpScript; } return balances; @@ -1086,18 +1115,15 @@ Value getaddressbalances(const Array& params, bool fHelp) if (params.size() > 1) nMinDepth = params[1].get_int(); - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; asset_amounts->Clear(); - mc_Buffer *genesis_amounts; - genesis_amounts=new mc_Buffer; + mc_Buffer *genesis_amounts=mc_gState->m_TmpBuffers->m_RpcBuffer1; genesis_amounts->Initialize(32,32+MC_AST_ASSET_QUANTITY_SIZE,MC_BUF_MODE_MAP); genesis_amounts->Clear(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); int last_size=0; Array assets; @@ -1274,10 +1300,6 @@ Value getaddressbalances(const Array& params, bool fHelp) } - delete lpScript; - delete asset_amounts; - delete genesis_amounts; - /* MCHN END */ return assets; } @@ -1333,18 +1355,15 @@ Value getassetbalances(const Array& params, bool fHelp) if (params.size() > 1) nMinDepth = params[1].get_int(); - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; asset_amounts->Clear(); - mc_Buffer *genesis_amounts; - genesis_amounts=new mc_Buffer; + mc_Buffer *genesis_amounts=mc_gState->m_TmpBuffers->m_RpcBuffer1; genesis_amounts->Initialize(32,32+MC_AST_ASSET_QUANTITY_SIZE,MC_BUF_MODE_MAP); genesis_amounts->Clear(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); int last_size=0; Array assets; @@ -1495,11 +1514,7 @@ Value getassetbalances(const Array& params, bool fHelp) asset_entry=AssetEntry(ptr,mc_GetLE(ptr+32,MC_AST_ASSET_QUANTITY_SIZE),0x00); assets.push_back(asset_entry); } - - delete lpScript; - delete asset_amounts; - delete genesis_amounts; - + /* MCHN END */ return assets; } @@ -1966,12 +1981,11 @@ Value getassettransaction(const Array& params, bool fHelp) } const CWalletTx& wtx=pwalletTxsMain->GetWalletTx(hash,NULL,NULL); - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; + asset_amounts->Clear(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); Object entry=ListAssetTransactions(wtx, &asset_entity, verbose, asset_amounts, lpScript); @@ -1980,8 +1994,6 @@ Value getassettransaction(const Array& params, bool fHelp) throw JSONRPCError(RPC_TX_NOT_FOUND, "This transaction was not found for this asset"); } - delete asset_amounts; - delete lpScript; return entry; } @@ -2045,16 +2057,14 @@ Value listassettransactions(const Array& params, bool fHelp) throw JSONRPCError(RPC_NOT_SUBSCRIBED, "Not subscribed to this asset"); } - mc_Buffer *entity_rows; - entity_rows=new mc_Buffer; - entity_rows->Initialize(MC_TDB_ENTITY_KEY_SIZE,MC_TDB_ROW_SIZE,MC_BUF_MODE_DEFAULT); + mc_Buffer *entity_rows=mc_gState->m_TmpBuffers->m_RpcEntityRows; + entity_rows->Clear(); - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; + asset_amounts->Clear(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); pwalletTxsMain->GetList(&entStat.m_Entity,1,1,entity_rows); shift=1; @@ -2109,9 +2119,5 @@ Value listassettransactions(const Array& params, bool fHelp) } } - delete entity_rows; - delete asset_amounts; - delete lpScript; - return retArray; } diff --git a/src/rpc/rpcblockchain.cpp b/src/rpc/rpcblockchain.cpp index 31a605f4..f80fb3a1 100644 --- a/src/rpc/rpcblockchain.cpp +++ b/src/rpc/rpcblockchain.cpp @@ -30,6 +30,7 @@ vector ParseBlockSetIdentifier(Value blockset_identifier); bool CreateAssetBalanceList(const CTxOut& out,mc_Buffer *amounts,mc_Script *lpScript); Object AssetEntry(const unsigned char *txid,int64_t quantity,uint32_t output_level); Array PermissionEntries(const CTxOut& txout,mc_Script *lpScript,bool fLong); +Array PerOutputDataEntries(const CTxOut& txout,mc_Script *lpScript,uint256 txid,int vout); string EncodeHexTx(const CTransaction& tx); int OrphanPoolSize(); bool paramtobool(Value param); @@ -514,12 +515,10 @@ Value gettxout(const Array& params, bool fHelp) /* MCHN START */ - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); - - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; + + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); asset_amounts->Clear(); CTxOut txout=coins.vout[n]; @@ -556,11 +555,21 @@ Value gettxout(const Array& params, bool fHelp) assets.push_back(asset_entry); } - ret.push_back(Pair("assets", assets)); + if( (assets.size() > 0) || (mc_gState->m_Compatibility & MC_VCM_1_0) ) + { + ret.push_back(Pair("assets", assets)); + } } Array permissions=PermissionEntries(txout,lpScript,false); - ret.push_back(Pair("permissions", permissions)); - + if( (permissions.size() > 0) || (mc_gState->m_Compatibility & MC_VCM_1_0) ) + { + ret.push_back(Pair("permissions", permissions)); + } + Array data=PerOutputDataEntries(txout,lpScript,hash,n); + if(data.size()) + { + ret.push_back(Pair("data", data)); + } /* MCHN END */ return ret; diff --git a/src/rpc/rpcexchange.cpp b/src/rpc/rpcexchange.cpp index d2c84c77..b30f9860 100644 --- a/src/rpc/rpcexchange.cpp +++ b/src/rpc/rpcexchange.cpp @@ -114,6 +114,13 @@ Object ExchangeAssetEntry(uint256 hash,const CTxOut txout,mc_Script *lpScript,mc { address=CBitcoinAddress(*lpKeyID); address_found=true; + if(mc_gState->m_Permissions->CanReceive(NULL,(unsigned char*)(lpKeyID)) == 0) + { + if(strError.size() == 0) + { + strError="Address doesn't have receive permission"; + } + } } else { @@ -122,16 +129,14 @@ Object ExchangeAssetEntry(uint256 hash,const CTxOut txout,mc_Script *lpScript,mc strError="Only pay-to-keyhash addresses are supported in exchange"; } } - if(mc_gState->m_Permissions->CanReceive(NULL,(unsigned char*)(lpKeyID)) == 0) - { - if(strError.size() == 0) - { - strError="Address doesn't have receive permission"; - } - } } } + if(strError.size()) + { + return result; + } + Array assets; asset_amounts->Clear(); @@ -214,13 +219,11 @@ Object DecodeExchangeTransaction(const CTransaction tx,int verbose,int64_t& nati vector input_txouts; vector input_errors; - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer2; asset_amounts->Clear(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript4; + lpScript->Clear(); AcceptExchange(tx, input_txouts, input_errors,strError); @@ -340,9 +343,6 @@ Object DecodeExchangeTransaction(const CTransaction tx,int verbose,int64_t& nati } - delete lpScript; - delete asset_amounts; - is_complete=true; if(lpAssets != NULL) { @@ -487,8 +487,8 @@ Object DecodeExchangeTransaction(const CTransaction tx,int verbose,int64_t& nati { CTxDestination address=CTxDestination(pkey.GetID()); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript4; + lpScript->Clear(); Value param=tocomplete; uint256 offer_hash; @@ -537,8 +537,6 @@ Object DecodeExchangeTransaction(const CTransaction tx,int verbose,int64_t& nati result.push_back(Pair("cancomplete", true)); } } - - delete lpScript; } } @@ -615,8 +613,8 @@ Value createrawexchange(const json_spirit::Array& params, bool fHelp) COutPoint offer_input; - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); CAmount nAmount=0; int eErrorCode; string strError=FindExchangeOutPoint(params,0,offer_input,nAmount,lpScript,&eErrorCode); @@ -712,9 +710,6 @@ Value createrawexchange(const json_spirit::Array& params, bool fHelp) } } - delete lpScript; - - return EncodeHexTx(tx); } @@ -725,8 +720,8 @@ Value appendrawexchange(const json_spirit::Array& params, bool fHelp) throw runtime_error("Help message not found\n"); COutPoint offer_input; - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); CAmount nAmount=0; int eErrorCode; @@ -825,14 +820,11 @@ Value appendrawexchange(const json_spirit::Array& params, bool fHelp) throw JSONRPCError(RPC_WALLET_ERROR, "Signing transaction failed"); } } - delete lpScript; bool is_complete=true; int64_t native_balance; - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; asset_amounts->Clear(); { @@ -842,8 +834,6 @@ Value appendrawexchange(const json_spirit::Array& params, bool fHelp) decode_result=DecodeExchangeTransaction(tx,0,native_balance,asset_amounts,is_complete,false,strError); } - delete asset_amounts; - Object result; result.push_back(Pair("hex", EncodeHexTx(tx))); result.push_back(Pair("complete", is_complete)); @@ -857,8 +847,8 @@ Value completerawexchange(const json_spirit::Array& params, bool fHelp) throw runtime_error("Help message not found\n"); COutPoint offer_input; - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); CAmount nAmount=0; int eErrorCode; @@ -984,14 +974,11 @@ Value completerawexchange(const json_spirit::Array& params, bool fHelp) throw JSONRPCError(RPC_WALLET_ERROR, "Signing transaction failed"); } } - delete lpScript; bool is_complete=true; int64_t native_balance; - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; asset_amounts->Clear(); { @@ -1000,8 +987,6 @@ Value completerawexchange(const json_spirit::Array& params, bool fHelp) decode_result=DecodeExchangeTransaction(tx,0,native_balance,asset_amounts,is_complete,true,strError); } - - delete asset_amounts; if(!is_complete) { @@ -1036,9 +1021,7 @@ Value decoderawexchange(const json_spirit::Array& params, bool fHelp) int64_t native_balance; string strError; - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; asset_amounts->Clear(); { @@ -1046,8 +1029,6 @@ Value decoderawexchange(const json_spirit::Array& params, bool fHelp) result=DecodeExchangeTransaction(tx,verbose,native_balance,asset_amounts,is_complete,true,strError); } - - delete asset_amounts; return result; } diff --git a/src/rpc/rpchelp.cpp b/src/rpc/rpchelp.cpp index 8bfe2813..f4ca707e 100644 --- a/src/rpc/rpchelp.cpp +++ b/src/rpc/rpchelp.cpp @@ -1404,7 +1404,15 @@ void mc_InitRPCHelpMap06() "3. open (boolean, required ) Should be false\n" "4 custom-fields (object, required) a json object with custom fields\n" " {\n" - " \"protocol-version\": version (numeric, required) Protocol version to upgrade to\n" + " \"protocol-version\": version (numeric, optional) Protocol version to upgrade to\n" + " \"parameter-name\": value (numeric, optional) New value for upgradable parameter, one of the following: \n" + " target-block-time,\n" + " maximum-block-size,\n" + " max-std-tx-size,\n" + " max-std-op-returns-count,\n" + " max-std-op-return-size,\n" + " max-std-op-drops-count,\n" + " max-std-element-size\n" " \"startblock\": block (numeric, optional, default 0) Block to apply from \n" // " \"param-name\": \"param-value\" (strings, required) The key is the parameter name, the value is parameter value\n" " ,...\n" @@ -1439,7 +1447,15 @@ void mc_InitRPCHelpMap06() "4. open (boolean, required ) Should be false\n" "5 custom-fields (object, required) a json object with custom fields\n" " {\n" - " \"protocol-version\": version (numeric, required) Protocol version to upgrade to \n" + " \"protocol-version\": version (numeric, optional) Protocol version to upgrade to \n" + " \"parameter-name\": value (numeric, optional) New value for upgradable parameter, one of the following: \n" + " target-block-time,\n" + " maximum-block-size,\n" + " max-std-tx-size,\n" + " max-std-op-returns-count,\n" + " max-std-op-return-size,\n" + " max-std-op-drops-count,\n" + " max-std-element-size\n" " \"start-block\": block (numeric, optional, default 0) Block to apply from \n" // " \"param-name\": \"param-value\" (strings, required) The key is the parameter name, the value is parameter value\n" " ,...\n" @@ -2025,7 +2041,7 @@ void mc_InitRPCHelpMap09() "1. \"address(es)\" (string, required) The multichain addresses to send to (comma delimited)\n" "2. \"permission(s)\" (string, required) Permission strings, comma delimited. \n" " Global: " + AllowedPermissions() + " \n" - " or per-asset: asset-identifier.issue,admin \n" + " or per-asset: asset-identifier.issue,admin,activate,send,receive \n" " or per-stream: stream-identifier.write,activate,admin \n" "3. native-amount (numeric, optional) Native currency amount to send. eg 0.1. Default - 0.0\n" "4. startblock (numeric, optional) Block to apply permissions from (inclusive). Default - 0\n" @@ -2054,7 +2070,7 @@ void mc_InitRPCHelpMap09() "2. \"to-address(es)\" (string, required) The multichain addresses to grant permissions to\n" "3. \"permission(s)\" (string, required) Permission strings, comma delimited. \n" " Global: " + AllowedPermissions() + " \n" - " or per-asset: asset-identifier.issue,admin \n" + " or per-asset: asset-identifier.issue,admin,activate,send,receive \n" " or per-stream: stream-identifier.write,activate,admin \n" "4. native-amount (numeric, optional) Native currency amount to send. eg 0.1. Default - 0.0\n" "5. startblock (numeric, optional) Block to apply permissions from (inclusive). Default - 0\n" @@ -2080,7 +2096,7 @@ void mc_InitRPCHelpMap09() "1. \"address(es)\" (string, required) The multichain addresses to send to (comma delimited)\n" "2. \"permission(s)\" (string, required) Permission strings, comma delimited. \n" " Global: " + AllowedPermissions() + " \n" - " or per-asset: asset-identifier.issue,admin \n" + " or per-asset: asset-identifier.issue,admin,activate,send,receive \n" " or per-stream: stream-identifier.write,activate,admin \n" "3. data|publish-new-stream-item (string or object, required) Data, see help data-with for details. \n" "4. native-amount (numeric, optional) Native currency amount to send. eg 0.1. Default - 0.0\n" @@ -2106,7 +2122,7 @@ void mc_InitRPCHelpMap10() "1. \"address(es)\" (string, required) The multichain addresses to send to (comma delimited)\n" "2. \"permission(s)\" (string, required) Permission strings, comma delimited. \n" " Global: " + AllowedPermissions() + " \n" - " or per-asset: asset-identifier.issue,admin \n" + " or per-asset: asset-identifier.issue,admin,activate,send,receive \n" " or per-stream: stream-identifier.write,activate,admin \n" "3. data|publish-new-stream-item (string or object, required) Data, see help data-with for details. \n" "4. native-amount (numeric, optional) Native currency amount to send. eg 0.1. Default - 0.0\n" @@ -2130,7 +2146,7 @@ void mc_InitRPCHelpMap10() "2. \"address(es)\" (string, required) The multichain addresses to send to (comma delimited)\n" "3. \"permission(s)\" (string, required) Permission strings, comma delimited. \n" " Global: " + AllowedPermissions() + " \n" - " or per-asset: asset-identifier.issue,admin \n" + " or per-asset: asset-identifier.issue,admin,activate,send,receive \n" " or per-stream: stream-identifier.write,activate,admin \n" "4. data|publish-new-stream-item (string or object, required) Data, see help data-with for details. \n" "5. native-amount (numeric, optional) Native currency amount to send. eg 0.1. Default - 0.0\n" @@ -2154,7 +2170,7 @@ void mc_InitRPCHelpMap10() "2. \"address(es)\" (string, required) The multichain addresses to send to (comma delimited)\n" "3. \"permission(s)\" (string, required) Permission strings, comma delimited. \n" " Global: " + AllowedPermissions() + " \n" - " or per-asset: asset-identifier.issue,admin \n" + " or per-asset: asset-identifier.issue,admin,activate,send,receive \n" " or per-stream: stream-identifier.write,activate,admin \n" "4. data|publish-new-stream-item (string or object, required) Data, see help data-with for details. \n" "5. native-amount (numeric, optional) Native currency amount to send. eg 0.1. Default - 0.0\n" @@ -2237,6 +2253,7 @@ void mc_InitRPCHelpMap10() " {\n" " \"name\" : \"asset-name\" (string, optional) Asset name\n" " \"open\" : true|false (boolean, optional, default false) True if follow-on issues are allowed\n" + " \"restrict\" : \"restrictions\" (string, optional) Permission strings, comma delimited. Possible values: send,receive\n" " ,...\n" " }\n" "3. quantity (numeric, required) The asset total amount in display units. eg. 1234.56\n" @@ -2268,6 +2285,7 @@ void mc_InitRPCHelpMap10() " {\n" " \"name\" : \"asset-name\" (string, optional) Asset name\n" " \"open\" : true|false (boolean, optional, default false) True if follow-on issues are allowed\n" + " \"restrict\" : \"restrictions\" (string, optional) Permission strings, comma delimited. Possible values: send,receive\n" " ,...\n" " }\n" "4. quantity (numeric, required) The asset total amount in display units. eg. 1234.56\n" @@ -2895,7 +2913,7 @@ void mc_InitRPCHelpMap13() " \"asset-identifier\" : asset-quantity\n" " ,...\n" " }\n" - "2. lock (boolean, optiona, default=true) Lock prepared unspent output\n" + "2. lock (boolean, optional, default=true) Lock prepared unspent output\n" "\nResult:\n" "{\n" " \"txid\": \"transactionid\", (string) Transaction ID of the output which can be spent in createrawexchange or createrawexchange\n" @@ -2998,7 +3016,7 @@ void mc_InitRPCHelpMap13() "1. \"address(es)\" (string, required) The addresses(es) to revoke permissions from\n" "2. \"permission(s)\" (string, required) Permission strings, comma delimited. \n" " Global: " + AllowedPermissions() + " \n" - " or per-asset: asset-identifier.issue,admin \n" + " or per-asset: asset-identifier.issue,admin,activate,send,receive \n" " or per-stream: stream-identifier.write,activate,admin \n" "3. native-amount (numeric, optional) native currency amount to send. eg 0.1. Default - 0\n" "4. \"comment\" (string, optional) A comment used to store what the transaction is for. \n" @@ -3023,7 +3041,7 @@ void mc_InitRPCHelpMap13() "2. \"to-address(es)\" (string, required) The addresses(es) to revoke permissions from. Comma delimited\n" "3. \"permission(s)\" (string, required) Permission strings, comma delimited. \n" " Global: " + AllowedPermissions() + " \n" - " or per-asset: asset-identifier.issue,admin \n" + " or per-asset: asset-identifier.issue,admin,activate,send,receive \n" " or per-stream: stream-identifier.write,activate,admin \n" "4. native-amount (numeric, optional) native currency amount to send. eg 0.1. Default - 0\n" "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n" @@ -3686,6 +3704,7 @@ void mc_InitRPCHelpMap16() " \"name\" : \"asset-name\" (string, optional) Asset name\n" " \"multiple\" : n (numeric, optional, default 1) Number of raw units in one displayed unit\n" " \"open\" : true|false (boolean, optional, default false) True if follow-on issues are allowed\n" + " \"restrict\" : \"restrictions\" (string, optional) Permission strings, comma delimited. Possible values: send,receive\n" " \"details\" : (object, optional) A json object with custom fields\n" " {\n" " \"param-name\": \"param-value\" (strings, required) The key is the parameter name, the value is parameter value\n" @@ -3741,7 +3760,15 @@ void mc_InitRPCHelpMap16() " \"startblock\" : n (numeric, optional, default: 0) Block to apply upgrade from (inclusive).\n" " \"details\" : (object, optional) A json object with custom fields\n" " {\n" - " \"protocol-version\": version (numeric, required) Protocol version to upgrade to \n" + " \"protocol-version\": version (numeric, optional) Protocol version to upgrade to \n" + " \"parameter-name\": value (numeric, optional) New value for upgradable parameter, one of the following: \n" + " target-block-time,\n" + " maximum-block-size,\n" + " max-std-tx-size,\n" + " max-std-op-returns-count,\n" + " max-std-op-return-size,\n" + " max-std-op-drops-count,\n" + " max-std-element-size\n" " }\n" " }\n" " or\n" @@ -3824,7 +3851,25 @@ void mc_InitRPCHelpMap16() " \"timestamp\" : n (numeric, optional) This helps resolve conflicts between\n" " permissions assigned by the same administrator. Default - current time\n" " }\n" - " }\n" + " }\n" + " or \n" + " { (object) A json object describing inline data\n" + " \"data\" : \n" + " {\n" + " \"data-hex\" (string, required) Data hex string\n" + " or\n" + " data-json (object, required) JSON data object\n" + " {\n" + " \"json\" : data-json (object, required) Valid JSON object\n" + " }\n" + " or\n" + " data-text (object, required) Text data object\n" + " {\n" + " \"text\" : \"data-text\" (string, required) Data string\n" + " }\n" + " }\n" + " }\n" + " ,...\n" "}\n" )); diff --git a/src/rpc/rpcmining.cpp b/src/rpc/rpcmining.cpp index def05c13..e6789920 100644 --- a/src/rpc/rpcmining.cpp +++ b/src/rpc/rpcmining.cpp @@ -171,7 +171,8 @@ Value setgenerate(const Array& params, bool fHelp) while (nHeight < nHeightEnd) { int canMine=0; - auto_ptr pblocktemplate(CreateNewBlockWithDefaultKey(pwalletMain,&canMine,lpMinerAddresses)); + CBlockIndex *pindexPrev; + auto_ptr pblocktemplate(CreateNewBlockWithDefaultKey(pwalletMain,&canMine,lpMinerAddresses,&pindexPrev)); // auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); if (!pblocktemplate.get()) { @@ -196,7 +197,7 @@ Value setgenerate(const Array& params, bool fHelp) { LOCK(cs_main); /* MCHN START */ - IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce,pwalletMain); + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce,pwalletMain); // IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); /* MCHN START */ } diff --git a/src/rpc/rpcmisc.cpp b/src/rpc/rpcmisc.cpp index 50e76b87..b7f4ca98 100644 --- a/src/rpc/rpcmisc.cpp +++ b/src/rpc/rpcmisc.cpp @@ -516,7 +516,6 @@ Value getblockchainparams(const json_spirit::Array& params, bool fHelp) if (fHelp || params.size() > 2) // MCHN throw runtime_error("Help message not found\n"); - bool fDisplay = true; if (params.size() > 0) fDisplay = params[0].get_bool(); @@ -569,6 +568,7 @@ Value getblockchainparams(const json_spirit::Array& params, bool fHelp) Value param_value; unsigned char* ptr; int size; + bool hidden=false; string param_string="";; ptr=(unsigned char*)mc_gState->m_NetworkParams->GetParam((mc_gState->m_NetworkParams->m_lpParams+i)->m_Name,&size); @@ -648,6 +648,13 @@ Value getblockchainparams(const json_spirit::Array& params, bool fHelp) else { param_value=mc_GetLE(ptr,4); + if((mc_gState->m_NetworkParams->m_lpParams+i)->m_Type & MC_PRM_HIDDEN) + { + if(mc_GetLE(ptr,4) == (mc_gState->m_NetworkParams->m_lpParams+i)->m_DefaultIntegerValue) + { + hidden=true; + } + } } break; case MC_PRM_INT64: @@ -662,15 +669,46 @@ Value getblockchainparams(const json_spirit::Array& params, bool fHelp) { param_value=Value::null; } - if(strcmp("protocolversion",(mc_gState->m_NetworkParams->m_lpParams+i)->m_Name) == 0) + if(nHeight) { - if(nHeight) + if(strcmp("protocolversion",(mc_gState->m_NetworkParams->m_lpParams+i)->m_Name) == 0) { param_value=mc_gState->m_NetworkParams->m_ProtocolVersion; } + if(strcmp("maximumblocksize",(mc_gState->m_NetworkParams->m_lpParams+i)->m_Name) == 0) + { + param_value=(int)MAX_BLOCK_SIZE; + } + if(strcmp("targetblocktime",(mc_gState->m_NetworkParams->m_lpParams+i)->m_Name) == 0) + { + param_value=(int)MCP_TARGET_BLOCK_TIME; + } + if(strcmp("maxstdtxsize",(mc_gState->m_NetworkParams->m_lpParams+i)->m_Name) == 0) + { + param_value=(int)MAX_STANDARD_TX_SIZE; + } + if(strcmp("maxstdopreturnscount",(mc_gState->m_NetworkParams->m_lpParams+i)->m_Name) == 0) + { + param_value=(int)MCP_MAX_STD_OP_RETURN_COUNT; + } + if(strcmp("maxstdopreturnsize",(mc_gState->m_NetworkParams->m_lpParams+i)->m_Name) == 0) + { + param_value=(int)MAX_OP_RETURN_RELAY; + } + if(strcmp("maxstdopdropscount",(mc_gState->m_NetworkParams->m_lpParams+i)->m_Name) == 0) + { + param_value=(int)MCP_STD_OP_DROP_COUNT; + } + if(strcmp("maxstdelementsize",(mc_gState->m_NetworkParams->m_lpParams+i)->m_Name) == 0) + { + param_value=(int)MAX_SCRIPT_ELEMENT_SIZE; + } } - obj.push_back(Pair(param_name,param_value)); + if(!hidden) + { + obj.push_back(Pair(param_name,param_value)); + } } } diff --git a/src/rpc/rpcpermissions.cpp b/src/rpc/rpcpermissions.cpp index c6507cd9..8e6e688e 100644 --- a/src/rpc/rpcpermissions.cpp +++ b/src/rpc/rpcpermissions.cpp @@ -52,8 +52,8 @@ Value grantoperation(const Array& params) if (params.size() > 8 && params[8].type() != null_type && !params[8].get_str().empty()) wtx.mapValue["to"] = params[8].get_str(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); uint32_t type,from,to,timestamp; @@ -117,7 +117,8 @@ Value grantoperation(const Array& params) LogPrintf("mchn: Granting %s permission(s) to address %s (%ld-%ld), Entity TxID: %s, Name: %s\n",permission_type,params[1].get_str(),from,to, ((uint256*)entity.GetTxID())->ToString().c_str(),entity.GetName()); - type=mc_gState->m_Permissions->GetPermissionType(permission_type.c_str(),entity.GetEntityType()); +// type=mc_gState->m_Permissions->GetPermissionType(permission_type.c_str(),entity.GetEntityType()); + type=mc_gState->m_Permissions->GetPermissionType(permission_type.c_str(),&entity); if(type == 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid permission"); @@ -126,7 +127,8 @@ Value grantoperation(const Array& params) } else { - type=mc_gState->m_Permissions->GetPermissionType(permission_type.c_str(),MC_ENT_TYPE_NONE); + type=mc_gState->m_Permissions->GetPermissionType(permission_type.c_str(),&entity); +// type=mc_gState->m_Permissions->GetPermissionType(permission_type.c_str(),MC_ENT_TYPE_NONE); if(type == 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid permission"); @@ -300,7 +302,6 @@ Value grantoperation(const Array& params) SendMoneyToSeveralAddresses(addresses, nAmount, wtx, lpScript, scriptOpReturn, fromaddresses); - delete lpScript; return wtx.GetHash().GetHex(); } @@ -472,7 +473,8 @@ Value listpermissions(const Array& params, bool fHelp) lpEntity=entity.GetTxID(); } - type=mc_gState->m_Permissions->GetPermissionType(permission_type.c_str(),entity.GetEntityType()); +// type=mc_gState->m_Permissions->GetPermissionType(permission_type.c_str(),entity.GetEntityType()); + type=mc_gState->m_Permissions->GetPermissionType(permission_type.c_str(),&entity); if(type == 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid permission"); diff --git a/src/rpc/rpcrawdata.cpp b/src/rpc/rpcrawdata.cpp index 2c5ffa36..6562ce2f 100644 --- a/src/rpc/rpcrawdata.cpp +++ b/src/rpc/rpcrawdata.cpp @@ -283,7 +283,7 @@ CScript RawDataScriptRawHex(Value *param,int *errorCode,string *strError) return scriptOpReturn; } -vector ParseRawFormattedData(const Value *value,uint32_t *data_format,mc_Script *lpDetailsScript,int *errorCode,string *strError) +vector ParseRawFormattedData(const Value *value,uint32_t *data_format,mc_Script *lpDetailsScript,bool allow_formatted,int *errorCode,string *strError) { vector vValue; if(value->type() == str_type) @@ -302,7 +302,7 @@ vector ParseRawFormattedData(const Value *value,uint32_t *data_fo } else { - if(mc_gState->m_Features->FormattedData()) + if(allow_formatted || (mc_gState->m_Features->FormattedData() != 0) ) { if(value->type() == obj_type) { @@ -368,6 +368,10 @@ vector ParseRawFormattedData(const Value *value,uint32_t *data_fo else { *strError=string("data should be hexadecimal string"); + if(mc_gState->m_Features->FormattedData() == 0) + { + *strError+=" for this protocol version"; + } } } @@ -486,7 +490,7 @@ CScript RawDataScriptFormatted(Value *param,uint32_t *data_format,mc_Script *lpD { *strError=string("data object should have single key - json or text"); } - vValue=ParseRawFormattedData(param,data_format,lpDetailsScript,errorCode,strError); + vValue=ParseRawFormattedData(param,data_format,lpDetailsScript,false,errorCode,strError); field_parsed=true; missing_data=false; } @@ -525,6 +529,7 @@ CScript RawDataScriptIssue(Value *param,mc_Script *lpDetails,mc_Script *lpDetail string entity_name; int multiple=1; int is_open=0; + uint32_t permissions=0; bool missing_name=true; bool missing_multiple=true; bool missing_open=true; @@ -606,6 +611,38 @@ CScript RawDataScriptIssue(Value *param,mc_Script *lpDetails,mc_Script *lpDetail missing_open=false; field_parsed=true; } + if(d.name_ == "restrict") + { + if(mc_gState->m_Features->PerAssetPermissions() == 0) + { + throw JSONRPCError(RPC_NOT_SUPPORTED, "Per-asset permissions not supported for this protocol version"); + } + if(permissions == 0) + { + if(d.value_.type() == str_type) + { + permissions=mc_gState->m_Permissions->GetPermissionType(d.value_.get_str().c_str(),MC_PTP_SEND | MC_PTP_RECEIVE); + if(permissions == 0) + { + *strError=string("Invalid restrict"); + } + } + else + { + *strError=string("Invalid restrict"); + } + } + else + { + *strError=string("restrict field can appear only once in the object"); + } + if(permissions) + { + lpDetails->SetSpecialParamValue(MC_ENT_SPRM_PERMISSIONS,(unsigned char*)&permissions,1); + } + field_parsed=true; + } + if(d.name_ == "details") { if(!missing_details) @@ -857,6 +894,98 @@ CScript RawDataScriptCreateStream(Value *param,mc_Script *lpDetails,mc_Script *l return scriptOpReturn; } +bool AddParamNameValueToScript(const string param_name,const Value param_value,mc_Script *lpDetailsScript,int version,int *errorCode,string *strError) +{ + + int64_t value; + string name=param_name; + name.erase(std::remove(name.begin(), name.end(), '-'), name.end()); + const mc_OneMultichainParam *param=mc_gState->m_NetworkParams->FindParam(name.c_str()); + + if(param == NULL) + { + *errorCode=RPC_INVALID_PARAMETER; + *strError=string("Invalid parameter name"); + return false; + } + + int size; + unsigned char zero=0; + switch(param->m_Type & MC_PRM_DATA_TYPE_MASK) + { + case MC_PRM_BOOLEAN: + if(param_value.type() == bool_type) + { + value=param_value.get_bool() ? 1 : 0; + } + else + { + *errorCode=RPC_INVALID_PARAMETER; + *strError=string("Invalid parameter type, should be boolean"); + return false; + } + break; + case MC_PRM_INT32: + case MC_PRM_INT64: + case MC_PRM_UINT32: + if(param->m_Type & MC_PRM_DECIMAL) + { + if(param_value.type() == real_type) + { + value=mc_gState->m_NetworkParams->DecimalToInt64(param_value.get_real()); + } + else + { + *errorCode=RPC_INVALID_PARAMETER; + *strError=string("Invalid parameter type, should be numeric"); + return false; + } + } + else + { + if(param_value.type() == int_type) + { + value=param_value.get_int64(); + } + else + { + *errorCode=RPC_INVALID_PARAMETER; + *strError=string("Invalid parameter type, should be integer"); + return false; + } + } + break; + default: + *errorCode=RPC_NOT_SUPPORTED; + *strError=string("One of parameters cannot be upgraded by this protocol version"); + return false; + } + + size=mc_gState->m_NetworkParams->CanBeUpgradedByVersion(name.c_str(),version,0); + + if(size < 0) + { + *errorCode=RPC_INVALID_PARAMETER; + *strError=string("Invalid parameter name"); + return false; + } + + if(size == 0) + { + *errorCode=RPC_NOT_SUPPORTED; + *strError=string("One of parameters cannot be upgraded by this protocol version"); + return false; + } + + lpDetailsScript->SetData((unsigned char*)name.c_str(),name.size()); + lpDetailsScript->SetData((unsigned char*)&zero,1); + lpDetailsScript->SetData((unsigned char*)&size,MC_PRM_PARAM_SIZE_BYTES); + lpDetailsScript->SetData((unsigned char*)&value,size); + + return true; +} + + CScript RawDataScriptCreateUpgrade(Value *param,mc_Script *lpDetails,mc_Script *lpDetailsScript,int *errorCode,string *strError) { CScript scriptOpReturn=CScript(); @@ -869,10 +998,14 @@ CScript RawDataScriptCreateUpgrade(Value *param,mc_Script *lpDetails,mc_Script * bool missing_name=true; bool missing_startblock=true; + bool missing_details=true; lpDetails->Clear(); lpDetails->AddElement(); - + + lpDetailsScript->Clear(); + lpDetailsScript->AddElement(); + protocol_version=-1; BOOST_FOREACH(const Pair& d, param->get_obj()) @@ -929,7 +1062,7 @@ CScript RawDataScriptCreateUpgrade(Value *param,mc_Script *lpDetails,mc_Script * } if(d.name_ == "details") { - if(protocol_version > 0) + if(!missing_details) { *strError=string("details field can appear only once in the object"); } @@ -942,7 +1075,10 @@ CScript RawDataScriptCreateUpgrade(Value *param,mc_Script *lpDetails,mc_Script * { if( (p.value_.type() == int_type) && (p.value_.get_int() > 0) ) { - protocol_version=p.value_.get_int(); + if(protocol_version < 0) + { + protocol_version=p.value_.get_int(); + } } else { @@ -951,21 +1087,39 @@ CScript RawDataScriptCreateUpgrade(Value *param,mc_Script *lpDetails,mc_Script * } else { - *strError=string("Invalid details"); + if(mc_gState->m_Features->ParameterUpgrades()) + { + AddParamNameValueToScript(p.name_,p.value_,lpDetailsScript,0,errorCode,strError); + } + else + { + *strError=string("Invalid details"); + } + } + } + + script = lpDetailsScript->GetData(0,&bytes); + if(strError->size() == 0) + { + if( (protocol_version <= 0) && (bytes == 0) ) + { + *strError=string("Missing protocol-version"); } } + if(strError->size() == 0) { if(protocol_version > 0) { lpDetails->SetSpecialParamValue(MC_ENT_SPRM_UPGRADE_PROTOCOL_VERSION,(unsigned char*)&protocol_version,4); } - else + if(bytes) { - *strError=string("Missing protocol-version"); - } + lpDetails->SetSpecialParamValue(MC_ENT_SPRM_UPGRADE_CHAIN_PARAMS,script,bytes); + } } - } + } + missing_details=false; field_parsed=true; } if(d.name_ == "create")field_parsed=true; @@ -977,9 +1131,9 @@ CScript RawDataScriptCreateUpgrade(Value *param,mc_Script *lpDetails,mc_Script * if(strError->size() == 0) { - if(protocol_version < 0) + if(missing_details) { - *strError=string("Missing protocol-version"); + *strError=string("Missing details"); } } @@ -987,6 +1141,7 @@ CScript RawDataScriptCreateUpgrade(Value *param,mc_Script *lpDetails,mc_Script * { int err; script=lpDetails->GetData(0,&bytes); + lpDetailsScript->Clear(); err=lpDetailsScript->SetNewEntityType(MC_ENT_TYPE_UPGRADE,0,script,bytes); if(err) { @@ -1067,7 +1222,7 @@ CScript RawDataScriptPublish(Value *param,mc_EntityDetails *entity,uint32_t *dat { *strError=string("data field can appear only once in the object"); } - vValue=ParseRawFormattedData(&(d.value_),data_format,lpDetailsScript,errorCode,strError); + vValue=ParseRawFormattedData(&(d.value_),data_format,lpDetailsScript,false,errorCode,strError); field_parsed=true; missing_data=false; } @@ -1329,12 +1484,10 @@ CScript ParseRawMetadata(Value param,uint32_t allowed_objects,mc_EntityDetails * uint32_t data_format; mc_EntityDetails entity; CScript scriptOpReturn=CScript(); - mc_Script *lpDetailsScript; - mc_Script *lpDetails; - - lpDetailsScript=NULL; - lpDetails=NULL; - + mc_Script *lpDetailsScript=mc_gState->m_TmpBuffers->m_RpcScript1; + lpDetailsScript->Clear(); + mc_Script *lpDetails=mc_gState->m_TmpBuffers->m_RpcScript2; + lpDetails->Clear(); uint32_t param_type=ParseRawDataParamType(¶m,given_entity,&entity,&data_format,&errorCode,&strError); if(strError.size()) @@ -1362,28 +1515,6 @@ CScript ParseRawMetadata(Value param,uint32_t allowed_objects,mc_EntityDetails * memcpy(found_entity,&entity,sizeof(mc_EntityDetails)); } - switch(param_type) - { - case MC_DATA_API_PARAM_TYPE_EMPTY_RAW: - case MC_DATA_API_PARAM_TYPE_RAW: - break; - default: - lpDetailsScript=new mc_Script; - break; - } - - switch(param_type) - { - case MC_DATA_API_PARAM_TYPE_ISSUE: - case MC_DATA_API_PARAM_TYPE_FOLLOWON: - case MC_DATA_API_PARAM_TYPE_CREATE_STREAM: - case MC_DATA_API_PARAM_TYPE_CREATE_UPGRADE: - lpDetails=new mc_Script; - break; - default: - break; - } - switch(param_type) { case MC_DATA_API_PARAM_TYPE_EMPTY_RAW: @@ -1418,14 +1549,6 @@ CScript ParseRawMetadata(Value param,uint32_t allowed_objects,mc_EntityDetails * exitlbl: - if(lpDetailsScript) - { - delete lpDetailsScript; - } - if(lpDetails) - { - delete lpDetails; - } if(strError.size()) { throw JSONRPCError(errorCode, strError); diff --git a/src/rpc/rpcrawtransaction.cpp b/src/rpc/rpcrawtransaction.cpp index a376a7ec..2d5fe3b2 100644 --- a/src/rpc/rpcrawtransaction.cpp +++ b/src/rpc/rpcrawtransaction.cpp @@ -102,12 +102,11 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) entry.push_back(Pair("vin", vin)); /* MCHN START */ - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer2; + asset_amounts->Clear(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript4; + lpScript->Clear(); /* MCHN END */ Array vdata; @@ -355,6 +354,11 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) { out.push_back(Pair("permissions", permissions)); } + Array peroutputdata=PerOutputDataEntries(txout,lpScript,tx.GetHash(),i); + if(peroutputdata.size()) + { + out.push_back(Pair("data", peroutputdata)); + } Array items; Value data_item_entry=DataItemEntry(tx,i,streams_already_seen, 0x03); @@ -482,10 +486,6 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) entry.push_back(Pair("data", aFullFormatMetaData)); } - delete lpScript; - delete asset_amounts; - - if (hashBlock != 0) { entry.push_back(Pair("blockhash", hashBlock.GetHex())); BlockMap::iterator mi = mapBlockIndex.find(hashBlock); @@ -559,6 +559,9 @@ Value listunspent(const Array& params, bool fHelp) nMaxDepth = params[1].get_int64(); set setAddress; + set setAddressUints; + set *lpSetAddressUint=NULL; + CTxDestination dest; if (params.size() > 2) { Array inputs = params[2].get_array(); BOOST_FOREACH(Value& input, inputs) { @@ -567,17 +570,36 @@ Value listunspent(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid address: ")+input.get_str()); if (setAddress.count(address)) throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str()); - setAddress.insert(address); + setAddress.insert(address); + + dest=address.Get(); + const CKeyID *lpKeyID=boost::get (&dest); + const CScriptID *lpScriptID=boost::get (&dest); + if(lpKeyID) + { + setAddressUints.insert(*(uint160*)lpKeyID); + } + else + { + if(lpScriptID) + { + setAddressUints.insert(*(uint160*)lpScriptID); + } + } + } + + if(setAddressUints.size()) + { + lpSetAddressUint=&setAddressUints; } } /* MCHN START */ - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; + asset_amounts->Clear(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); { LOCK(pwalletMain->cs_wallet); @@ -589,7 +611,7 @@ Value listunspent(const Array& params, bool fHelp) vector vecOutputs; assert(pwalletMain != NULL); // pwalletMain->AvailableCoins(vecOutputs, false); - pwalletMain->AvailableCoins(vecOutputs, false, NULL, true, true); + pwalletMain->AvailableCoins(vecOutputs, false, NULL, true, true, 0, lpSetAddressUint); BOOST_FOREACH(const COutput& out, vecOutputs) { if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) continue; @@ -689,6 +711,13 @@ Value listunspent(const Array& params, bool fHelp) } Array permissions=PermissionEntries(txout,lpScript,false); entry.push_back(Pair("permissions", permissions)); + + Array peroutputdata=PerOutputDataEntries(txout,lpScript,hash,out.i); + if(peroutputdata.size()) + { + entry.push_back(Pair("data", peroutputdata)); + } + // entry.push_back(Pair("spendable", out.fSpendable)); /* MCHN END */ results.push_back(entry); @@ -696,9 +725,6 @@ Value listunspent(const Array& params, bool fHelp) /* MCHN START */ - delete lpScript; - delete asset_amounts; - /* MCHN END */ return results; } @@ -749,15 +775,13 @@ Value appendrawchange(const Array& params, bool fHelp) } } - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); - mc_Buffer *amounts; - amounts=new mc_Buffer; - mc_InitABufferMap(amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; + asset_amounts->Clear(); + mc_Buffer *amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer2; + amounts->Clear(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); int allowed=0; int required=0; @@ -933,10 +957,6 @@ Value appendrawchange(const Array& params, bool fHelp) } } - delete lpScript; - delete asset_amounts; - delete amounts; - return EncodeHexTx(txNew); } @@ -1093,9 +1113,7 @@ void AddCacheInputScriptIfNeeded(CMutableTransaction& rawTx,Array inputs, bool f if(fNewOutputs) { - mc_Script *lpDetails; - lpDetails=new mc_Script; - + mc_Script *lpDetails=mc_gState->m_TmpBuffers->m_RpcScript4; lpDetails->Clear(); for(int i=0;i<(int)cache_array.size();i++) { diff --git a/src/rpc/rpcserver.cpp b/src/rpc/rpcserver.cpp index 83a886fd..5a18fc28 100644 --- a/src/rpc/rpcserver.cpp +++ b/src/rpc/rpcserver.cpp @@ -311,7 +311,18 @@ Value help(const Array& params, bool fHelp) string strCommand; if (params.size() > 0) strCommand = params[0].get_str(); - + + if(strCommand.size()) + { + if(setAllowedWhenLimited.size()) + { + if( setAllowedWhenLimited.count(strCommand) == 0 ) + { + throw JSONRPCError(RPC_NOT_ALLOWED, "Method not allowed with current setting of -rpcallowmethod runtime parameter"); + } + } + } + return tableRPC.help(strCommand); } @@ -357,8 +368,9 @@ uint32_t GetPausedServices(const char *str) if(ptr > start) { type=0; - if(memcmp(start,"incoming", ptr-start) == 0)type = MC_NPS_INCOMING; - if(memcmp(start,"mining", ptr-start) == 0)type = MC_NPS_MINING; + if(memcmp(start,"incoming", ptr-start) == 0)type = MC_NPS_INCOMING; + if(memcmp(start,"mining", ptr-start) == 0)type = MC_NPS_MINING; + if(memcmp(start,"reaccepting", ptr-start) == 0)type = MC_NPS_REACCEPT; if(type == 0) { @@ -416,6 +428,11 @@ Value resumecmd(const Array& params, bool fHelp) mc_gState->m_NodePausedState &= (MC_NPS_ALL ^ type); + if( type & MC_NPS_REACCEPT ) + { + pwalletMain->ReacceptWalletTransactions(); + } + LogPrintf("Node paused state is set to %08X\n",mc_gState->m_NodePausedState); return "Resumed"; @@ -622,9 +639,27 @@ static ip::tcp::endpoint ParseEndpoint(const std::string &strEndpoint, int defau return ip::tcp::endpoint(asio::ip::address::from_string(addr), port); } +void mc_InitRPCListIfLimited() +{ + if (mapArgs.count("-rpcallowmethod")) + { + setAllowedWhenLimited.insert("help"); + BOOST_FOREACH(const std::string& methods, mapMultiArgs["-rpcallowmethod"]) + { + stringstream ss(methods); + string tok; + while(getline(ss, tok, ',')) + { + setAllowedWhenLimited.insert(tok); + } + } + } +} + void StartRPCThreads() { mc_InitRPCList(vStaticRPCCommands,vStaticRPCWalletReadCommands); + mc_InitRPCListIfLimited(); tableRPC.initialize(); rpc_allow_subnets.clear(); @@ -1134,6 +1169,14 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s } } + if(setAllowedWhenLimited.size()) + { + if( setAllowedWhenLimited.count(strMethod) == 0 ) + { + throw JSONRPCError(RPC_NOT_ALLOWED, "Method not allowed with current setting of -rpcallowmethod runtime parameter"); + } + } + // Observe safe mode string strWarning = GetWarnings("rpc"); if (strWarning != "" && !GetBoolArg("-disablesafemode", false) && @@ -1232,7 +1275,7 @@ std::string HelpExampleCli(string methodname, string args){ std::string HelpExampleRpc(string methodname, string args){ return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", " - "\"method\": \"" + std::string(mc_gState->m_NetworkParams->Name()) + " " + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:"+ + "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:"+ strprintf("%d",(int)mc_gState->m_NetworkParams->GetInt64Param("defaultrpcport")) + "\n";// MCHN was hard-coded 8332 before } @@ -1241,6 +1284,7 @@ std::map mapHelpStrings; std::map mapLogParamCounts; std::set setAllowedWhenWaitingForUpgrade; std::set setAllowedWhenOffline; +std::set setAllowedWhenLimited; std::vector vStaticRPCCommands; std::vector vStaticRPCWalletReadCommands; diff --git a/src/rpc/rpcserver.h b/src/rpc/rpcserver.h index e9e4a9ea..a0401fbc 100644 --- a/src/rpc/rpcserver.h +++ b/src/rpc/rpcserver.h @@ -124,6 +124,7 @@ extern std::map mapHelpStrings; extern std::map mapLogParamCounts; extern std::set setAllowedWhenWaitingForUpgrade; extern std::set setAllowedWhenOffline; +extern std::set setAllowedWhenLimited; extern std::vector vStaticRPCCommands; extern std::vector vStaticRPCWalletReadCommands; void mc_InitRPCHelpMap(); diff --git a/src/rpc/rpcstreams.cpp b/src/rpc/rpcstreams.cpp index 47ec0153..d93db3ae 100644 --- a/src/rpc/rpcstreams.cpp +++ b/src/rpc/rpcstreams.cpp @@ -270,12 +270,12 @@ Value createstreamfromcmd(const Array& params, bool fHelp) CWalletTx wtx; - mc_Script *lpScript; - - mc_Script *lpDetailsScript; - lpDetailsScript=NULL; - - mc_Script *lpDetails; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); + mc_Script *lpDetailsScript=mc_gState->m_TmpBuffers->m_RpcScript1; + lpDetailsScript->Clear(); + mc_Script *lpDetails=mc_gState->m_TmpBuffers->m_RpcScript2; + lpDetails->Clear(); int ret,type; string stream_name=""; @@ -322,9 +322,9 @@ Value createstreamfromcmd(const Array& params, bool fHelp) } } - lpScript=new mc_Script; + lpScript->Clear(); - lpDetails=new mc_Script; + lpDetails->Clear(); lpDetails->AddElement(); if(params[3].get_bool()) { @@ -361,7 +361,7 @@ Value createstreamfromcmd(const Array& params, bool fHelp) int errorCode=RPC_INVALID_PARAMETER; string strError; - lpDetailsScript=new mc_Script; + lpDetailsScript->Clear(); if (params.size() > 4) { ParseRawDetails(&(params[4]),lpDetails,lpDetailsScript,&errorCode,&strError); @@ -488,13 +488,6 @@ Value createstreamfromcmd(const Array& params, bool fHelp) exitlbl: - if(lpDetailsScript) - { - delete lpDetailsScript; - } - delete lpDetails; - delete lpScript; - if(strError.size()) { throw JSONRPCError(errorCode, strError); @@ -575,7 +568,9 @@ Value publishfrom(const Array& params, bool fHelp) throw JSONRPCError(RPC_NOT_SUPPORTED, "API is not supported for this protocol version"); } - mc_Script *lpScript; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); + mc_EntityDetails stream_entity; parseStreamIdentifier(params[1],&stream_entity); @@ -642,21 +637,28 @@ Value publishfrom(const Array& params, bool fHelp) } } - mc_Script *lpDetailsScript; - lpDetailsScript=NULL; - + if(keys.size() > 1) + { + if( mc_gState->m_Features->MultipleStreamKeys() == 0 ) + { + throw JSONRPCError(RPC_NOT_SUPPORTED, "Multiple keys are not supported by this protocol version"); + } + } + + mc_Script *lpDetailsScript=mc_gState->m_TmpBuffers->m_RpcScript1; + lpDetailsScript->Clear(); + uint32_t data_format=MC_SCR_DATA_FORMAT_UNKNOWN; vector dataData; - lpDetailsScript=new mc_Script; + lpDetailsScript->Clear(); string strError; int errorCode=RPC_INVALID_PARAMETER; - dataData=ParseRawFormattedData(&(params[3]),&data_format,lpDetailsScript,&errorCode,&strError); + dataData=ParseRawFormattedData(&(params[3]),&data_format,lpDetailsScript,false,&errorCode,&strError); if(strError.size()) { - delete lpDetailsScript; throw JSONRPCError(errorCode, strError); } @@ -705,16 +707,13 @@ Value publishfrom(const Array& params, bool fHelp) } - lpScript=new mc_Script; + lpScript->Clear(); EnsureWalletIsUnlocked(); LOCK (pwalletMain->cs_wallet_send); SendMoneyToSeveralAddresses(addresses, 0, wtx, lpScript, scriptOpReturn,fromaddresses); - delete lpDetailsScript; - delete lpScript; - return wtx.GetHash().GetHex(); } @@ -841,8 +840,7 @@ Value unsubscribe(const Array& params, bool fHelp) inputEntities.push_back(entity_to_subscribe); } - mc_Buffer *streams; - streams=new mc_Buffer; + mc_Buffer *streams=mc_gState->m_TmpBuffers->m_RpcBuffer1; streams->Initialize(sizeof(mc_TxEntity),sizeof(mc_TxEntity),MC_BUF_MODE_DEFAULT); @@ -888,12 +886,10 @@ Value unsubscribe(const Array& params, bool fHelp) { if(pwalletTxsMain->Unsubscribe(streams)) { - delete streams; throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't unsubscribe from stream"); } } - delete streams; return Value::null; } @@ -988,7 +984,7 @@ int mc_GetHashAndFirstOutput(mc_TxEntityRow *lpEntTx,uint256 *hash) erow.m_Pos=lpEntTx->m_Pos; first_output=(int)mc_GetLE(lpEntTx->m_TxId+MC_TEE_OFFSET_IN_TXID,sizeof(uint32_t)); count=(int)mc_GetLE(lpEntTx->m_TxId+MC_TEE_OFFSET_IN_TXID+sizeof(uint32_t),sizeof(uint32_t)); - if(erow.m_Pos > count) + if((int)erow.m_Pos > count) { erow.m_Pos-=count; if(pwalletTxsMain->GetRow(&erow) == 0) @@ -1059,9 +1055,8 @@ Value liststreamitems(const Array& params, bool fHelp) throw JSONRPCError(RPC_NOT_SUBSCRIBED, "Not subscribed to this stream"); } - mc_Buffer *entity_rows; - entity_rows=new mc_Buffer; - entity_rows->Initialize(MC_TDB_ENTITY_KEY_SIZE,MC_TDB_ROW_SIZE,MC_BUF_MODE_DEFAULT); + mc_Buffer *entity_rows=mc_gState->m_TmpBuffers->m_RpcEntityRows; + entity_rows->Clear(); mc_AdjustStartAndCount(&count,&start,entStat.m_LastPos); @@ -1082,8 +1077,6 @@ Value liststreamitems(const Array& params, bool fHelp) } } - delete entity_rows; - return retArray; } @@ -1176,9 +1169,8 @@ Value liststreamblockitems(const Array& params, bool fHelp) height_from=heights[0]; height_to=heights[0]; - mc_Buffer *entity_rows; - entity_rows=new mc_Buffer; - entity_rows->Initialize(MC_TDB_ENTITY_KEY_SIZE,MC_TDB_ROW_SIZE,MC_BUF_MODE_DEFAULT); + mc_Buffer *entity_rows=mc_gState->m_TmpBuffers->m_RpcEntityRows; + entity_rows->Clear(); for(unsigned int i=1;iInitialize(MC_TDB_ENTITY_KEY_SIZE,MC_TDB_ROW_SIZE,MC_BUF_MODE_DEFAULT); + mc_Buffer *entity_rows=mc_gState->m_TmpBuffers->m_RpcEntityRows; + entity_rows->Clear(); Object empty_object; Object obj; @@ -1498,14 +1488,16 @@ Value getstreamsummary(const Array& params, bool fPublisher) } else { + if( (mode & MC_VMM_IGNORE) == 0) + { + err=MC_ERR_INVALID_PARAMETER_VALUE; + } obj.push_back(Pair("json", empty_object)); } result=obj; exitlbl: - delete entity_rows; - if(err) { throw JSONRPCError(RPC_NOT_ALLOWED, "Some items to be merged are in the wrong format (try using \'ignore\')" ); @@ -1610,9 +1602,8 @@ Value liststreamkeyitems(const Array& params, bool fHelp) getSubKeyEntityFromKey(params[1].get_str(),entStat,&entity); - mc_Buffer *entity_rows; - entity_rows=new mc_Buffer; - entity_rows->Initialize(MC_TDB_ENTITY_KEY_SIZE,MC_TDB_ROW_SIZE,MC_BUF_MODE_DEFAULT); + mc_Buffer *entity_rows=mc_gState->m_TmpBuffers->m_RpcEntityRows; + entity_rows->Clear(); mc_AdjustStartAndCount(&count,&start,pwalletTxsMain->GetListSize(&entity,entStat.m_Generation,NULL)); @@ -1633,8 +1624,6 @@ Value liststreamkeyitems(const Array& params, bool fHelp) } } - delete entity_rows; - return retArray; } @@ -1719,9 +1708,8 @@ Value liststreampublisheritems(const Array& params, bool fHelp) const char *key_ptr=key_string.c_str(); getSubKeyEntityFromPublisher(params[1].get_str(),entStat,&entity); - mc_Buffer *entity_rows; - entity_rows=new mc_Buffer; - entity_rows->Initialize(MC_TDB_ENTITY_KEY_SIZE,MC_TDB_ROW_SIZE,MC_BUF_MODE_DEFAULT); + mc_Buffer *entity_rows=mc_gState->m_TmpBuffers->m_RpcEntityRows; + entity_rows->Clear(); mc_AdjustStartAndCount(&count,&start,pwalletTxsMain->GetListSize(&entity,entStat.m_Generation,NULL)); @@ -1742,8 +1730,6 @@ Value liststreampublisheritems(const Array& params, bool fHelp) } } - delete entity_rows; - return retArray; } @@ -1760,20 +1746,19 @@ Value liststreammap_operation(mc_TxEntity *parent_entity,vector& in mc_TxEntity entity; mc_TxEntityStat entStat; Array retArray; - mc_Buffer *entity_rows; + mc_Buffer *entity_rows=mc_gState->m_TmpBuffers->m_RpcEntityRows; mc_TxEntityRow erow; uint160 stream_subkey_hash; int row,enitity_count; const char **given_key; const char **given_publisher; - entity_rows=NULL; + entity_rows->Clear(); enitity_count=inputEntities.size(); if(enitity_count == 0) { mc_AdjustStartAndCount(&count,&start,pwalletTxsMain->GetListSize(parent_entity,NULL)); - entity_rows=new mc_Buffer; - entity_rows->Initialize(MC_TDB_ENTITY_KEY_SIZE,MC_TDB_ROW_SIZE,MC_BUF_MODE_DEFAULT); + entity_rows->Clear(); pwalletTxsMain->GetList(parent_entity,start+1,count,entity_rows); enitity_count=entity_rows->GetCount(); } @@ -1794,7 +1779,7 @@ Value liststreammap_operation(mc_TxEntity *parent_entity,vector& in { mc_TxEntityRow *lpEntTx; string key_string; - if(entity_rows) + if(entity_rows->GetCount()) { lpEntTx=(mc_TxEntityRow*)entity_rows->GetRow(i); key_string=pwalletTxsMain->GetSubKey(lpEntTx->m_TxId, NULL,NULL); @@ -1870,11 +1855,6 @@ Value liststreammap_operation(mc_TxEntity *parent_entity,vector& in retArray.push_back(all_entry); } - if(entity_rows) - { - delete entity_rows; - } - return retArray; } diff --git a/src/rpc/rpcupgrades.cpp b/src/rpc/rpcupgrades.cpp index 84abb5cd..3fb04023 100644 --- a/src/rpc/rpcupgrades.cpp +++ b/src/rpc/rpcupgrades.cpp @@ -6,6 +6,8 @@ #include "rpc/rpcwallet.h" +bool AddParamNameValueToScript(const string param_name,const Value param_value,mc_Script *lpDetailsScript,int version,int *errorCode,string *strError); +int CreateUpgradeLists(int current_height,vector *vParams,vector *vUpgrades); Value createupgradefromcmd(const Array& params, bool fHelp) { @@ -22,16 +24,18 @@ Value createupgradefromcmd(const Array& params, bool fHelp) CWalletTx wtx; - mc_Script *lpScript; - - mc_Script *lpDetailsScript; - lpDetailsScript=NULL; - - mc_Script *lpDetails; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); + mc_Script *lpDetailsScript=mc_gState->m_TmpBuffers->m_RpcScript1; + lpDetailsScript->Clear(); + mc_Script *lpDetails=mc_gState->m_TmpBuffers->m_RpcScript2; + lpDetails->Clear(); int ret,type; string upgrade_name=""; - + string strError=""; + int errorCode=RPC_INVALID_PARAMETER; + if (params[2].type() != str_type) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid upgrade name, should be string"); @@ -71,9 +75,68 @@ Value createupgradefromcmd(const Array& params, bool fHelp) } } - lpScript=new mc_Script; + vector addresses; + + vector fromaddresses; + + if(params[0].get_str() != "*") + { + fromaddresses=ParseAddresses(params[0].get_str(),false,false); + + if(fromaddresses.size() != 1) + { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Single from-address should be specified"); + } + + if( (IsMine(*pwalletMain, fromaddresses[0]) & ISMINE_SPENDABLE) != ISMINE_SPENDABLE ) + { + throw JSONRPCError(RPC_WALLET_ADDRESS_NOT_FOUND, "Private key for from-address is not found in this wallet"); + } + + set thisFromAddresses; + + BOOST_FOREACH(const CTxDestination& fromaddress, fromaddresses) + { + thisFromAddresses.insert(fromaddress); + } + + CPubKey pkey; + if(!pwalletMain->GetKeyFromAddressBook(pkey,MC_PTP_CREATE | MC_PTP_ADMIN,&thisFromAddresses)) + { + throw JSONRPCError(RPC_INSUFFICIENT_PERMISSIONS, "from-address doesn't have create or admin permission"); + } + } + else + { + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook) + { + const CBitcoinAddress& address = item.first; + CKeyID keyID; + + if(address.GetKeyID(keyID)) + { + if( IsMine(*pwalletMain, keyID) & ISMINE_SPENDABLE ) + { + if(mc_gState->m_Permissions->CanCreate(NULL,(unsigned char*)(&keyID))) + { + if(mc_gState->m_Permissions->CanAdmin(NULL,(unsigned char*)(&keyID))) + { + fromaddresses.push_back(keyID); + } + } + } + } + } + CPubKey pkey; + if(fromaddresses.size() == 0) + { + throw JSONRPCError(RPC_INSUFFICIENT_PERMISSIONS, "This wallet doesn't have keys with create and admin permission"); + } + } - lpDetails=new mc_Script; + lpScript->Clear(); + + lpDetails->Clear(); lpDetails->AddElement(); if(upgrade_name.size()) { @@ -89,6 +152,10 @@ Value createupgradefromcmd(const Array& params, bool fHelp) bool protocol_version_found=false; int protocol_version; int start_block; + CScript scriptOpReturn=CScript(); + + lpDetailsScript->Clear(); + lpDetailsScript->AddElement(); if(params[4].type() == obj_type) { @@ -99,19 +166,31 @@ Value createupgradefromcmd(const Array& params, bool fHelp) { if(s.value_.type() != int_type) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid protocol version, expecting integer"); + strError="Invalid protocol version, expecting integer"; + goto exitlbl; } protocol_version_found=true; protocol_version=s.value_.get_int(); if( (protocol_version < mc_gState->MinProtocolVersion()) || ( -mc_gState->VersionInfo(protocol_version) != mc_gState->GetNumericVersion() ) ) { - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid value for protocol version. Valid range: %s\n",mc_SupportedProtocols().c_str())); + strError=strprintf("Invalid value for protocol version. Valid range: %s\n",mc_SupportedProtocols().c_str()); + goto exitlbl; } if( protocol_version < mc_gState->MinProtocolDowngradeVersion() ) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid protocol version, cannot downgrade to this version"); + strError="Invalid protocol version, cannot downgrade to this version"; + goto exitlbl; + } + if( mc_gState->m_NetworkParams->ProtocolVersion() >= mc_gState->MinProtocolForbiddenDowngradeVersion() ) + { + if(protocol_version < mc_gState->m_NetworkParams->ProtocolVersion()) + { + strError="Invalid protocol version, cannot downgrade from current version"; + errorCode=RPC_NOT_ALLOWED; + goto exitlbl; + } } lpDetails->SetSpecialParamValue(MC_ENT_SPRM_UPGRADE_PROTOCOL_VERSION,(unsigned char*)&protocol_version,4); } @@ -121,122 +200,91 @@ Value createupgradefromcmd(const Array& params, bool fHelp) { if(s.value_.type() != int_type) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start block, expecting integer"); + strError="Invalid start block, expecting integer"; + goto exitlbl; } start_block=s.value_.get_int(); lpDetails->SetSpecialParamValue(MC_ENT_SPRM_UPGRADE_START_BLOCK,(unsigned char*)&start_block,4); } else { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter name"); + if(mc_gState->m_Features->ParameterUpgrades()) + { + if(!AddParamNameValueToScript(s.name_,s.value_,lpDetailsScript,0,&errorCode,&strError)) + { + goto exitlbl; + } + } + else + { + strError="Some upgrade parameters are not supported by the current protocol, please upgrade protocol separately first."; + goto exitlbl; + } // lpDetails->SetParamValue(s.name_.c_str(),s.name_.size(),(unsigned char*)s.value_.get_str().c_str(),s.value_.get_str().size()); } } } + } else { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid custom fields, expecting object"); + strError="Invalid custom fields, expecting object"; + goto exitlbl; } - if(!protocol_version_found) + size_t bytes; + const unsigned char *script; + + script = lpDetailsScript->GetData(0,&bytes); + if( !protocol_version_found && (bytes == 0) ) + { + strError="Missing protocol-version"; + if(mc_gState->m_Features->ParameterUpgrades()) + { + strError+=" or other parameters"; + } + + goto exitlbl; + } + + if(bytes) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "protocol-version is required"); + lpDetails->SetSpecialParamValue(MC_ENT_SPRM_UPGRADE_CHAIN_PARAMS,script,bytes); } - size_t bytes; - const unsigned char *script; script=lpDetails->GetData(0,&bytes); - lpDetailsScript=new mc_Script; int err; size_t elem_size; const unsigned char *elem; - CScript scriptOpReturn=CScript(); + lpDetailsScript->Clear(); err=lpDetailsScript->SetNewEntityType(MC_ENT_TYPE_UPGRADE,0,script,bytes); if(err) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid custom fields or upgrade name, too long"); + strError="Invalid custom fields or upgrade name, too long"; + goto exitlbl; } elem = lpDetailsScript->GetData(0,&elem_size); scriptOpReturn << vector(elem, elem + elem_size) << OP_DROP << OP_RETURN; - vector addresses; - - vector fromaddresses; - if(params[0].get_str() != "*") + EnsureWalletIsUnlocked(); { - fromaddresses=ParseAddresses(params[0].get_str(),false,false); - - if(fromaddresses.size() != 1) - { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Single from-address should be specified"); - } - - if( (IsMine(*pwalletMain, fromaddresses[0]) & ISMINE_SPENDABLE) != ISMINE_SPENDABLE ) - { - throw JSONRPCError(RPC_WALLET_ADDRESS_NOT_FOUND, "Private key for from-address is not found in this wallet"); - } - - set thisFromAddresses; + LOCK (pwalletMain->cs_wallet_send); - BOOST_FOREACH(const CTxDestination& fromaddress, fromaddresses) - { - thisFromAddresses.insert(fromaddress); - } - - CPubKey pkey; - if(!pwalletMain->GetKeyFromAddressBook(pkey,MC_PTP_CREATE | MC_PTP_ADMIN,&thisFromAddresses)) - { - throw JSONRPCError(RPC_INSUFFICIENT_PERMISSIONS, "from-address doesn't have create or admin permission"); - } + SendMoneyToSeveralAddresses(addresses, 0, wtx, lpScript, scriptOpReturn,fromaddresses); } - else - { - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook) - { - const CBitcoinAddress& address = item.first; - CKeyID keyID; - - if(address.GetKeyID(keyID)) - { - if( IsMine(*pwalletMain, keyID) & ISMINE_SPENDABLE ) - { - if(mc_gState->m_Permissions->CanCreate(NULL,(unsigned char*)(&keyID))) - { - if(mc_gState->m_Permissions->CanAdmin(NULL,(unsigned char*)(&keyID))) - { - fromaddresses.push_back(keyID); - } - } - } - } - } - CPubKey pkey; - if(fromaddresses.size() == 0) - { - throw JSONRPCError(RPC_INSUFFICIENT_PERMISSIONS, "This wallet doesn't have keys with create and admin permission"); - } - } - - - EnsureWalletIsUnlocked(); - LOCK (pwalletMain->cs_wallet_send); - - SendMoneyToSeveralAddresses(addresses, 0, wtx, lpScript, scriptOpReturn,fromaddresses); + +exitlbl: - if(lpDetailsScript) + if(strError.size()) { - delete lpDetailsScript; + throw JSONRPCError(errorCode, strError); } - delete lpDetails; - delete lpScript; - return wtx.GetHash().GetHex(); } @@ -267,6 +315,17 @@ Value approvefrom(const json_spirit::Array& params, bool fHelp) mc_EntityDetails entity; entity.Zero(); ParseEntityIdentifier(entity_identifier,&entity, MC_ENT_TYPE_UPGRADE); + + if( mc_gState->m_NetworkParams->ProtocolVersion() >= mc_gState->MinProtocolForbiddenDowngradeVersion() ) + { + if(entity.UpgradeProtocolVersion()) + { + if(entity.UpgradeProtocolVersion() < mc_gState->m_NetworkParams->ProtocolVersion()) + { + throw JSONRPCError(RPC_NOT_ALLOWED, "Invalid protocol version, cannot downgrade from current version"); + } + } + } if(mc_gState->m_Permissions->IsApproved(entity.GetTxID()+MC_AST_SHORT_TXID_OFFSET,0)) { @@ -298,8 +357,8 @@ Value approvefrom(const json_spirit::Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Please use raw transactions to approve upgrades from P2SH addresses"); } - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); lpScript->SetEntity(entity.GetTxID()+MC_AST_SHORT_TXID_OFFSET); lpScript->SetApproval(approval, timestamp); @@ -325,7 +384,6 @@ Value approvefrom(const json_spirit::Array& params, bool fHelp) SendMoneyToSeveralAddresses(addresses, 0, wtx, lpScript, scriptOpReturn, fromaddresses); - delete lpScript; return wtx.GetHash().GetHex(); } @@ -338,6 +396,203 @@ Value listupgrades(const json_spirit::Array& params, bool fHelp) Array results; mc_Buffer *upgrades; + set inputUpgrades; + + upgrades=NULL; + + + vector inputStrings; + if (params.size() > 0 && params[0].type() != null_type && ((params[0].type() != str_type) || (params[0].get_str() !="*" ) ) ) + { + if(params[0].type() == str_type) + { + inputStrings.push_back(params[0].get_str()); + if(params[0].get_str() == "") + { + return results; + } + } + else + { + inputStrings=ParseStringList(params[0]); + if(inputStrings.size() == 0) + { + return results; + } + } + } + + for(int is=0;is<(int)inputStrings.size();is++) + { + string param=inputStrings[is]; + + mc_EntityDetails upgrade_entity; + ParseEntityIdentifier(param,&upgrade_entity, MC_ENT_TYPE_UPGRADE); + + uint160 hash=0; + memcpy(&hash,upgrade_entity.GetTxID() + MC_AST_SHORT_TXID_OFFSET,MC_AST_SHORT_TXID_SIZE); + inputUpgrades.insert(hash); + } + + vector vParams; + vector vUpgrades; + uint32_t current_height=chainActive.Height(); + CreateUpgradeLists(chainActive.Height(),&vParams,&vUpgrades); + + for(int u=0;u<(int)vUpgrades.size();u++) + { + Object entry; + Object applied_params; + Object skipped_params; + mc_PermissionDetails *plsRow; + mc_PermissionDetails *plsDet; + mc_EntityDetails upgrade_entity; + int flags,consensus,remaining; + Value null_value; + string param_name; + + uint160 hash=0; + memcpy(&hash,vUpgrades[u].m_EntityShortTxID,sizeof(uint160)); + + if( (inputUpgrades.size() == 0) || (inputUpgrades.count(hash) > 0) ) + { + upgrade_entity.Zero(); + mc_gState->m_Assets->FindEntityByShortTxID(&upgrade_entity,vUpgrades[u].m_EntityShortTxID); + entry=UpgradeEntry(upgrade_entity.GetTxID()); + + entry.push_back(Pair("approved", (vUpgrades[u].m_ApprovedBlock <= current_height+1))); + + for(uint32_t p=vUpgrades[u].m_FirstParam;pm_DisplayName); + if(vParams[p].m_Skipped == MC_PSK_APPLIED) + { + if(vParams[p].m_Param->m_Type & MC_PRM_DECIMAL) + { + applied_params.push_back(Pair(param_name,mc_gState->m_NetworkParams->Int64ToDecimal(vParams[p].m_Value))); + } + else + { + switch(vParams[p].m_Param->m_Type & MC_PRM_DATA_TYPE_MASK) + { + case MC_PRM_BOOLEAN: + applied_params.push_back(Pair(param_name,(vParams[p].m_Value != 0))); + break; + case MC_PRM_INT32: + applied_params.push_back(Pair(param_name,(int)vParams[p].m_Value)); + case MC_PRM_UINT32: + case MC_PRM_INT64: + applied_params.push_back(Pair(param_name,vParams[p].m_Value)); + break; + } + } + } + else + { + string param_err; + switch(vParams[p].m_Skipped) + { + case MC_PSK_INTERNAL_ERROR: param_err="Parameter not applied because of internal error, please report this"; break; + case MC_PSK_NOT_FOUND: param_err="Parameter name not recognized"; break; + case MC_PSK_WRONG_SIZE: param_err="Parameter is encoded with wrong size"; break; + case MC_PSK_OUT_OF_RANGE: param_err="Parameter value is out of range"; break; + case MC_PSK_FRESH_UPGRADE: param_err=strprintf("Parameter is upgraded less than %d blocks ago",MIN_BLOCKS_BETWEEN_UPGRADES); break; + case MC_PSK_DOUBLE_RANGE: param_err="New parameter value must be between half and double previous value"; break; + case MC_PSK_NOT_SUPPORTED: param_err="This parameter cannot be upgraded in this protocol version"; break; + case MC_PSK_NEW_NOT_DOWNGRADABLE: param_err="Cannot downgrade to this version"; break; + case MC_PSK_OLD_NOT_DOWNGRADABLE: param_err="Downgrades are not allowed in this protocol version"; break; + default: param_err="Parameter not applied because of internal error, please report this"; break; + } + skipped_params.push_back(Pair(param_name,param_err)); + } + } + + if(vUpgrades[u].m_AppliedBlock <= current_height) + { + entry.push_back(Pair("appliedblock", (int64_t)vUpgrades[u].m_AppliedBlock)); + entry.push_back(Pair("appliedparams", applied_params)); + entry.push_back(Pair("skippedparams", skipped_params)); + } + else + { + entry.push_back(Pair("appliedblock", null_value)); + entry.push_back(Pair("appliedparams", null_value)); + entry.push_back(Pair("skippedparams", null_value)); + } + + upgrades=mc_gState->m_Permissions->GetUpgradeList(upgrade_entity.GetTxID() + MC_AST_SHORT_TXID_OFFSET,upgrades); + if(upgrades->GetCount()) + { + plsRow=(mc_PermissionDetails *)(upgrades->GetRow(upgrades->GetCount()-1)); + flags=plsRow->m_Flags; + consensus=plsRow->m_RequiredAdmins; + if(plsRow->m_Type != MC_PTP_UPGRADE) + { + plsRow->m_BlockTo=0; + } + + Array admins; + Array pending; + mc_Buffer *details; + + if(plsRow->m_Type == MC_PTP_UPGRADE) + { + details=mc_gState->m_Permissions->GetPermissionDetails(plsRow); + } + else + { + details=NULL; + } + + if(details) + { + for(int j=0;jGetCount();j++) + { + plsDet=(mc_PermissionDetails *)(details->GetRow(j)); + remaining=plsDet->m_RequiredAdmins; + if(plsDet->m_BlockFrom < plsDet->m_BlockTo) + { + uint160 addr; + memcpy(&addr,plsDet->m_LastAdmin,sizeof(uint160)); + CKeyID lpKeyID=CKeyID(addr); + admins.push_back(CBitcoinAddress(lpKeyID).ToString()); + } + } + consensus=plsRow->m_RequiredAdmins; + } + if(admins.size() == 0) + { + if(plsRow->m_BlockFrom < plsRow->m_BlockTo) + { + uint160 addr; + memcpy(&addr,plsRow->m_LastAdmin,sizeof(uint160)); + CKeyID lpKeyID=CKeyID(addr); + admins.push_back(CBitcoinAddress(lpKeyID).ToString()); + } + } + + entry.push_back(Pair("admins", admins)); + entry.push_back(Pair("required", (int64_t)(consensus-admins.size()))); + } + upgrades->Clear(); + results.push_back(entry); + } + } + + mc_gState->m_Permissions->FreePermissionList(upgrades); + + return results; +} + +Value listupgrades_old(const json_spirit::Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error("Help message not found\n"); + + Array results; + mc_Buffer *upgrades; + int latest_version; + upgrades=NULL; @@ -420,6 +675,7 @@ Value listupgrades(const json_spirit::Array& params, bool fHelp) } } + latest_version=(int)mc_gState->m_NetworkParams->GetInt64Param("protocolversion"); BOOST_FOREACH(PAIRTYPE(const uint64_t, int)& item, map_sorted) { int i=item.second; @@ -454,7 +710,23 @@ Value listupgrades(const json_spirit::Array& params, bool fHelp) } if(current_height >=applied_height) { - entry.push_back(Pair("appliedblock",(int64_t)applied_height)); + if(upgrade_entity.UpgradeProtocolVersion()) + { + if((latest_version < mc_gState->MinProtocolForbiddenDowngradeVersion()) || (upgrade_entity.UpgradeProtocolVersion() >= latest_version)) + { + latest_version=upgrade_entity.UpgradeProtocolVersion(); + entry.push_back(Pair("appliedblock",(int64_t)applied_height)); + } + else + { + Value null_value; + entry.push_back(Pair("appliedblock",null_value)); + } + } + else + { + entry.push_back(Pair("appliedblock",(int64_t)applied_height)); + } } else { diff --git a/src/rpc/rpcutils.cpp b/src/rpc/rpcutils.cpp index b2aef927..e2b3ae9f 100644 --- a/src/rpc/rpcutils.cpp +++ b/src/rpc/rpcutils.cpp @@ -446,6 +446,42 @@ Value PermissionForFieldEntry(mc_EntityDetails *lpEntity) return Value::null; } +Array PerOutputDataEntries(const CTxOut& txout,mc_Script *lpScript,uint256 txid,int vout) +{ + Array results; + unsigned char *ptr; + int size; + + if(mc_gState->m_NetworkParams->IsProtocolMultichain() == 0) + { + return results; + } + + const CScript& script1 = txout.scriptPubKey; + CScript::const_iterator pc1 = script1.begin(); + + lpScript->Clear(); + lpScript->SetScript((unsigned char*)(&pc1[0]),(size_t)(script1.end()-pc1),MC_SCR_TYPE_SCRIPTPUBKEY); + + for (int e = 0; e < lpScript->GetNumElements(); e++) + { + lpScript->SetElement(e); + if(lpScript->GetRawData(&ptr,&size) == 0) + { + uint32_t format=MC_SCR_DATA_FORMAT_UNKNOWN; + if(e > 0) + { + lpScript->SetElement(e-1); + lpScript->GetDataFormat(&format); + } + results.push_back(OpReturnFormatEntry(ptr,size,txid,vout,format,NULL)); + } + } + + return results; +} + + Array PermissionEntries(const CTxOut& txout,mc_Script *lpScript,bool fLong) { Array results; @@ -486,7 +522,8 @@ Array PermissionEntries(const CTxOut& txout,mc_Script *lpScript,bool fLong) { Object entry; entry.push_back(Pair("for", PermissionForFieldEntry(&entity))); - full_type=mc_gState->m_Permissions->GetPossiblePermissionTypes(entity.GetEntityType()); +// full_type=mc_gState->m_Permissions->GetPossiblePermissionTypes(entity.GetEntityType()); + full_type=mc_gState->m_Permissions->GetPossiblePermissionTypes(&entity); if(full_type & MC_PTP_CONNECT)entry.push_back(Pair("connect", (type & MC_PTP_CONNECT) ? true : false)); if(full_type & MC_PTP_SEND)entry.push_back(Pair("send", (type & MC_PTP_SEND) ? true : false)); if(full_type & MC_PTP_RECEIVE)entry.push_back(Pair("receive", (type & MC_PTP_RECEIVE) ? true : false)); @@ -715,6 +752,64 @@ Object StreamEntry(const unsigned char *txid,uint32_t output_level) return entry; } +map ParamsToUpgrade(mc_EntityDetails *entity,int version) +{ + map result; + int size=0; + const mc_OneMultichainParam *param; + char* ptr=(char*)entity->GetParamUpgrades(&size); + char* ptrEnd; + string param_name; + int param_size,given_size; + int64_t param_value; + if(ptr) + { + ptrEnd=ptr+size; + while(ptrm_NetworkParams->FindParam(ptr); + ptr+=mc_gState->m_NetworkParams->GetParamFromScript(ptr,¶m_value,&given_size); + + if(strcmp(ptr,"protocolversion")) + { + if(param) + { + param_size=mc_gState->m_NetworkParams->CanBeUpgradedByVersion(param->m_Name,version,0); + if( (param_size > 0) && (param_size == given_size) ) + { + param_name=string(param->m_DisplayName); + if(result.find(param_name) == result.end()) + { + if(param->m_Type & MC_PRM_DECIMAL) + { + result.insert(make_pair(param_name, mc_gState->m_NetworkParams->Int64ToDecimal(param_value))); + } + else + { + switch(param->m_Type & MC_PRM_DATA_TYPE_MASK) + { + case MC_PRM_BOOLEAN: + result.insert(make_pair(param_name, (param_value != 0) )); + break; + case MC_PRM_INT32: + result.insert(make_pair(param_name, (int)param_value)); + case MC_PRM_UINT32: + case MC_PRM_INT64: + result.insert(make_pair(param_name, param_value)); + break; + } + } + } + } + } + } + } + } + + return result; +} + + Object UpgradeEntry(const unsigned char *txid) { Object entry; @@ -740,7 +835,15 @@ Object UpgradeEntry(const unsigned char *txid) } entry.push_back(Pair("createtxid", hash.GetHex())); Object fields; - fields.push_back(Pair("protocol-version",entity.UpgradeProtocolVersion())); + map params_to_upgrade=ParamsToUpgrade(&entity,0); + if(entity.UpgradeProtocolVersion()) + { + fields.push_back(Pair("protocol-version",entity.UpgradeProtocolVersion())); + } + for(map::iterator it = params_to_upgrade.begin(); it != params_to_upgrade.end(); ++it) + { + fields.push_back(Pair(it->first, it->second)); + } entry.push_back(Pair("params",fields)); entry.push_back(Pair("startblock",(int64_t)entity.UpgradeStartBlock())); @@ -1005,7 +1108,7 @@ Object AssetEntry(const unsigned char *txid,int64_t quantity,uint32_t output_lev // output_level constants // 0x0000 minimal: name, assetref, non-negative qty, negative actual issueqty // 0x0001 raw -// 0x0002 multiple, units, open, details +// 0x0002 multiple, units, open, details, permissions // 0x0004 issuetxid, // 0x0008 subscribed/synchronized // 0x0020 issuers @@ -1071,9 +1174,11 @@ Object AssetEntry(const unsigned char *txid,int64_t quantity,uint32_t output_lev uint64_t multiple=1; const unsigned char *ptr; double units=1.; + uint32_t permissions; ptr=entity.GetScript(); multiple=genesis_entity.GetAssetMultiple(); + permissions=genesis_entity.Permissions(); units= 1./(double)multiple; if(output_level & 0x0002) { @@ -1089,6 +1194,13 @@ Object AssetEntry(const unsigned char *txid,int64_t quantity,uint32_t output_lev { entry.push_back(Pair("open",false)); } + if(mc_gState->m_Features->PerAssetPermissions()) + { + Object pObject; + pObject.push_back(Pair("send",(permissions & MC_PTP_SEND) ? true : false)); + pObject.push_back(Pair("receive",(permissions & MC_PTP_RECEIVE) ? true : false)); + entry.push_back(Pair("restrict",pObject)); + } } } @@ -1284,10 +1396,10 @@ string ParseRawOutputObject(Value param,CAmount& nAmount,mc_Script *lpScript, in { string strError=""; unsigned char buf[MC_AST_ASSET_FULLREF_BUF_SIZE]; - mc_Buffer *lpBuffer; - mc_Buffer *lpFollowonBuffer; - lpBuffer=new mc_Buffer; - lpFollowonBuffer=new mc_Buffer; + mc_Buffer *lpBuffer=mc_gState->m_TmpBuffers->m_RpcABNoMapBuffer1; + lpBuffer->Clear(); + mc_Buffer *lpFollowonBuffer=mc_gState->m_TmpBuffers->m_RpcABNoMapBuffer2; + lpFollowonBuffer->Clear(); int assets_per_opdrop=(MAX_STANDARD_TX_SIZE)/(mc_gState->m_NetworkParams->m_AssetRefSize+MC_AST_ASSET_QUANTITY_SIZE); int32_t verify_level=-1; int asset_error=0; @@ -1304,9 +1416,6 @@ string ParseRawOutputObject(Value param,CAmount& nAmount,mc_Script *lpScript, in memset(buf,0,MC_AST_ASSET_FULLREF_BUF_SIZE); - mc_InitABufferDefault(lpBuffer); - mc_InitABufferDefault(lpFollowonBuffer); - if(mc_gState->m_Features->VerifySizeOfOpDropElements()) { if(mc_gState->m_Features->VerifySizeOfOpDropElements()) @@ -1317,7 +1426,8 @@ string ParseRawOutputObject(Value param,CAmount& nAmount,mc_Script *lpScript, in BOOST_FOREACH(const Pair& a, param.get_obj()) { - if(a.value_.type() == obj_type) + if( (a.value_.type() == obj_type) || + (( (a.value_.type() == str_type) || (a.value_.type() == array_type) ) && (a.name_== "data")) ) { bool parsed=false; @@ -1455,6 +1565,47 @@ string ParseRawOutputObject(Value param,CAmount& nAmount,mc_Script *lpScript, in lpScript->SetAssetQuantities(lpFollowonBuffer,MC_SCR_ASSET_SCRIPT_TYPE_FOLLOWON); parsed=true; } + + if(!parsed && (a.name_ == "data")) + { + Array arr; + if( (a.value_.type() == str_type) || (a.value_.type() == obj_type) ) + { + arr.push_back(a.value_); + } + else + { + if(a.value_.type() == array_type) + { + arr=a.value_.get_array(); + } + } + + for(int i=0;i<(int)arr.size();i++) + { + uint32_t data_format=MC_SCR_DATA_FORMAT_UNKNOWN; + int errorCode=RPC_INVALID_PARAMETER; + + mc_gState->m_TmpScript->Clear(); + + vector vData=ParseRawFormattedData(&(arr[i]),&data_format,mc_gState->m_TmpScript,true,&errorCode,&strError); + if(strError.size()) + { + if(eErrorCode) + { + *eErrorCode=errorCode; + } + goto exitlbl; + } + + if(data_format != MC_SCR_DATA_FORMAT_UNKNOWN) + { + lpScript->SetDataFormat(data_format); + } + lpScript->SetRawData(&(vData[0]),(int)vData.size()); + } + parsed=true; + } if(!parsed && (a.name_ == "permissions")) { @@ -1570,7 +1721,8 @@ string ParseRawOutputObject(Value param,CAmount& nAmount,mc_Script *lpScript, in if(type_string.size()) { - type=mc_gState->m_Permissions->GetPermissionType(type_string.c_str(),entity.GetEntityType()); + type=mc_gState->m_Permissions->GetPermissionType(type_string.c_str(),&entity); +// type=mc_gState->m_Permissions->GetPermissionType(type_string.c_str(),entity.GetEntityType()); if(entity.GetEntityType() == MC_ENT_TYPE_NONE) { if(required) @@ -1708,9 +1860,6 @@ string ParseRawOutputObject(Value param,CAmount& nAmount,mc_Script *lpScript, in break; } - delete lpBuffer; - delete lpFollowonBuffer; - return strError; } @@ -1853,6 +2002,11 @@ CScript GetScriptForString(string source) destinations.push_back(tok); } + if(destinations.size() == 0) + { + throw runtime_error(" Address cannot be empty"); + } + if(destinations.size() == 1) { CBitcoinAddress address(destinations[0]); @@ -1923,8 +2077,8 @@ vector > ParseRawOutputMultiObject(Object sendTo,int *re } else { - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript4; + lpScript->Clear(); // uint256 offer_hash; size_t elem_size; const unsigned char *elem; @@ -1953,7 +2107,6 @@ vector > ParseRawOutputMultiObject(Object sendTo,int *re else throw JSONRPCError(RPC_INTERNAL_ERROR, "Invalid script"); } - delete lpScript; } vecSend.push_back(make_pair(scriptPubKey, nAmount)); diff --git a/src/rpc/rpcutils.h b/src/rpc/rpcutils.h index a4e3f788..50d72971 100644 --- a/src/rpc/rpcutils.h +++ b/src/rpc/rpcutils.h @@ -85,6 +85,7 @@ int ParseAssetKeyToFullAssetRef(const char* asset_key,unsigned char *full_asset_ Array AddressEntries(const CTxIn& txin,txnouttype& typeRet,mc_Script *lpScript); Array AddressEntries(const CTxOut& txout,txnouttype& typeRet); Value PermissionForFieldEntry(mc_EntityDetails *lpEntity); +Array PerOutputDataEntries(const CTxOut& txout,mc_Script *lpScript,uint256 txid,int vout); Array PermissionEntries(const CTxOut& txout,mc_Script *lpScript,bool fLong); Object StreamEntry(const unsigned char *txid,uint32_t output_level); Object UpgradeEntry(const unsigned char *txid); @@ -107,7 +108,7 @@ void ParseRawAction(string action,bool& lock_it, bool& sign_it,bool& send_it); bool paramtobool(Value param); int paramtoint(Value param,bool check_for_min,int min_value,string error_message); vector ParseBlockSetIdentifier(Value blockset_identifier); -vector ParseRawFormattedData(const Value *value,uint32_t *data_format,mc_Script *lpDetailsScript,int *errorCode,string *strError); +vector ParseRawFormattedData(const Value *value,uint32_t *data_format,mc_Script *lpDetailsScript,bool allow_formatted,int *errorCode,string *strError); void ParseRawDetails(const Value *value,mc_Script *lpDetails,mc_Script *lpDetailsScript,int *errorCode,string *strError); bool mc_IsJsonObjectForMerge(const Value *value,int level); Value mc_MergeValues(const Value *value1,const Value *value2,uint32_t mode,int level,int *error); diff --git a/src/rpc/rpcwallet.cpp b/src/rpc/rpcwallet.cpp index d1c087be..aefa80c7 100644 --- a/src/rpc/rpcwallet.cpp +++ b/src/rpc/rpcwallet.cpp @@ -570,20 +570,46 @@ Value gettxoutdata(const Array& params, bool fHelp) mc_gState->m_TmpScript->Clear(); mc_gState->m_TmpScript->SetScript((unsigned char*)(&pc1[0]),(size_t)(script1.end()-pc1),MC_SCR_TYPE_SCRIPTPUBKEY); + uint32_t format; string metadata=""; + size_t elem_size; + const unsigned char *elem; if(mc_gState->m_TmpScript->IsOpReturnScript() == 0) { - throw JSONRPCError(RPC_OUTPUT_NOT_DATA, "Output without metadata"); + unsigned char *ptr; + int size; + elem=NULL; + + for (int e = 0; e < mc_gState->m_TmpScript->GetNumElements(); e++) + { + mc_gState->m_TmpScript->SetElement(e); + if(mc_gState->m_TmpScript->GetRawData(&ptr,&size) == 0) + { + if(elem) + { + throw JSONRPCError(RPC_NOT_ALLOWED, "This output has more than one data item"); + } + format=MC_SCR_DATA_FORMAT_UNKNOWN; + if(e > 0) + { + mc_gState->m_TmpScript->SetElement(e-1); + mc_gState->m_TmpScript->GetDataFormat(&format); + } + elem=ptr; + elem_size=size; + } + } + if(elem == NULL) + { + throw JSONRPCError(RPC_OUTPUT_NOT_DATA, "Output without metadata"); + } + } + else + { + mc_gState->m_TmpScript->ExtractAndDeleteDataFormat(&format); + elem = mc_gState->m_TmpScript->GetData(mc_gState->m_TmpScript->GetNumElements()-1,&elem_size); } - size_t elem_size; - const unsigned char *elem; - - uint32_t format; - - mc_gState->m_TmpScript->ExtractAndDeleteDataFormat(&format); - - elem = mc_gState->m_TmpScript->GetData(mc_gState->m_TmpScript->GetNumElements()-1,&elem_size); int count,start; count=elem_size; @@ -1457,36 +1483,6 @@ Value listtransactions(const Array& params, bool fHelp) if(mc_gState->m_WalletMode & MC_WMD_ADDRESS_TXS) { throw JSONRPCError(RPC_NOT_SUPPORTED, "Not supported with scalable wallet - if you need listtransactions, run multichaind -walletdbversion=1 -rescan, but the wallet will perform worse"); -/* - mc_Buffer *entity_rows; - entity_rows=new mc_Buffer; - entity_rows->Initialize(MC_TDB_ENTITY_KEY_SIZE,MC_TDB_ROW_SIZE,MC_BUF_MODE_DEFAULT); - - mc_TxEntity wallet_by_time; - mc_TxEntityRow *lpEntTx; - wallet_by_time.Zero(); - wallet_by_time.m_EntityType=MC_TET_TIMERECEIVED; - if(filter & ISMINE_WATCH_ONLY) - { - wallet_by_time.m_EntityType |= MC_TET_WALLET_ALL; - } - else - { - wallet_by_time.m_EntityType |= MC_TET_WALLET_SPENDABLE; - } - pwalletTxsMain->GetList(&wallet_by_time,-nFrom,nCount,entity_rows); - for(int i=entity_rows->GetCount()-1;i>=0;i--) - { - lpEntTx=(mc_TxEntityRow*)entity_rows->GetRow(i); - uint256 hash; - mc_TxDefRow txdef; - memcpy(&hash,lpEntTx->m_TxId,MC_TDB_TXID_SIZE); - const CWalletTx& wtx=pwalletTxsMain->GetWalletTx(hash,&txdef,NULL); - ListTransactions(wtx, strAccount, 0, true, ret, filter,&txdef); - } - delete entity_rows; - std::reverse(ret.begin(), ret.end()); // Return oldest to newest -*/ } else { diff --git a/src/rpc/rpcwalletsend.cpp b/src/rpc/rpcwalletsend.cpp index be1c3187..c2f3e925 100644 --- a/src/rpc/rpcwalletsend.cpp +++ b/src/rpc/rpcwalletsend.cpp @@ -201,13 +201,12 @@ Value sendfromaddress(const Array& params, bool fHelp) vector addresses; addresses.push_back(address.Get()); - mc_Script *lpScript; - - lpScript=NULL; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); if (params[2].type() == obj_type) { - lpScript=new mc_Script; + lpScript->Clear(); uint256 offer_hash; if (params[2].type() != obj_type) @@ -275,11 +274,6 @@ Value sendfromaddress(const Array& params, bool fHelp) SendMoneyToSeveralAddresses(addresses, nAmount, wtx, lpScript, CScript(), fromaddresses); - if(lpScript) - { - delete lpScript; - } - return wtx.GetHash().GetHex(); } @@ -307,13 +301,12 @@ Value sendwithmetadatafrom(const Array& params, bool fHelp) vector addresses; addresses.push_back(address.Get()); - mc_Script *lpScript; - - lpScript=NULL; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); if (params[2].type() == obj_type) { - lpScript=new mc_Script; + lpScript->Clear(); uint256 offer_hash; if (params[2].type() != obj_type) @@ -402,11 +395,6 @@ Value sendwithmetadatafrom(const Array& params, bool fHelp) SendMoneyToSeveralAddresses(addresses, nAmount, wtx, lpScript, scriptOpReturn, fromaddresses); - if(lpScript) - { - delete lpScript; - } - return wtx.GetHash().GetHex(); } @@ -623,8 +611,9 @@ Value preparelockunspentfrom(const json_spirit::Array& params, bool fHelp) vector addresses; addresses.push_back(CTxDestination(pkey.GetID())); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); + CAmount nAmount=0; uint256 offer_hash; bool lock_it=true; @@ -703,8 +692,6 @@ Value preparelockunspentfrom(const json_spirit::Array& params, bool fHelp) } } - delete lpScript; - if(lock_it) { @@ -737,8 +724,9 @@ Value preparelockunspent(const json_spirit::Array& params, bool fHelp) vector addresses; addresses.push_back(CTxDestination(pkey.GetID())); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); + CAmount nAmount=0; uint256 offer_hash; bool lock_it=true; @@ -820,9 +808,6 @@ Value preparelockunspent(const json_spirit::Array& params, bool fHelp) } } - delete lpScript; - - if(lock_it) { COutPoint outpt(wtx.GetHash(),vout); @@ -866,8 +851,8 @@ Value sendassetfrom(const Array& params, bool fHelp) throw JSONRPCError(RPC_INSUFFICIENT_PERMISSIONS, "Destination address doesn't have receive permission"); } - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); unsigned char buf[MC_AST_ASSET_FULLREF_BUF_SIZE]; memset(buf,0,MC_AST_ASSET_FULLREF_BUF_SIZE); @@ -902,18 +887,13 @@ Value sendassetfrom(const Array& params, bool fHelp) mc_SetABQuantity(buf,quantity); - mc_Buffer *lpBuffer; - lpBuffer=new mc_Buffer; - - mc_InitABufferDefault(lpBuffer); + mc_Buffer *lpBuffer=mc_gState->m_TmpBuffers->m_RpcABNoMapBuffer1; + lpBuffer->Clear(); lpBuffer->Add(buf); lpScript->SetAssetQuantities(lpBuffer,MC_SCR_ASSET_SCRIPT_TYPE_TRANSFER); - delete lpBuffer; - - vector addresses; addresses.push_back(address.Get()); @@ -961,8 +941,6 @@ Value sendassetfrom(const Array& params, bool fHelp) SendMoneyToSeveralAddresses(addresses, nAmount, wtx, lpScript, CScript(),fromaddresses); - delete lpScript; - return wtx.GetHash().GetHex(); } @@ -1004,8 +982,8 @@ Value sendassettoaddress(const Array& params, bool fHelp) throw JSONRPCError(RPC_INSUFFICIENT_PERMISSIONS, "Destination address doesn't have receive permission"); } - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); unsigned char buf[MC_AST_ASSET_FULLREF_BUF_SIZE]; memset(buf,0,MC_AST_ASSET_FULLREF_BUF_SIZE); @@ -1040,8 +1018,8 @@ Value sendassettoaddress(const Array& params, bool fHelp) mc_SetABQuantity(buf,quantity); - mc_Buffer *lpBuffer; - lpBuffer=new mc_Buffer; + mc_Buffer *lpBuffer=mc_gState->m_TmpBuffers->m_RpcABNoMapBuffer1; + lpBuffer->Clear(); mc_InitABufferDefault(lpBuffer); @@ -1049,9 +1027,6 @@ Value sendassettoaddress(const Array& params, bool fHelp) lpScript->SetAssetQuantities(lpBuffer,MC_SCR_ASSET_SCRIPT_TYPE_TRANSFER); - delete lpBuffer; - - vector addresses; addresses.push_back(address.Get()); @@ -1062,7 +1037,5 @@ Value sendassettoaddress(const Array& params, bool fHelp) SendMoneyToSeveralAddresses(addresses, nAmount, wtx, lpScript, CScript(),fromaddresses); - delete lpScript; - return wtx.GetHash().GetHex(); } diff --git a/src/rpc/rpcwallettxs.cpp b/src/rpc/rpcwallettxs.cpp index 65bd7a2c..a20507bd 100644 --- a/src/rpc/rpcwallettxs.cpp +++ b/src/rpc/rpcwallettxs.cpp @@ -497,16 +497,14 @@ Value listwallettransactions(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from"); - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; + asset_amounts->Clear(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); - mc_Buffer *entity_rows; - entity_rows=new mc_Buffer; - entity_rows->Initialize(MC_TDB_ENTITY_KEY_SIZE,MC_TDB_ROW_SIZE,MC_BUF_MODE_DEFAULT); + mc_Buffer *entity_rows=mc_gState->m_TmpBuffers->m_RpcEntityRows; + entity_rows->Clear(); Array ret; if(mc_gState->m_WalletMode & MC_WMD_ADDRESS_TXS) @@ -574,11 +572,6 @@ Value listwallettransactions(const Array& params, bool fHelp) } - delete lpScript; - delete asset_amounts; - delete entity_rows; - - return ret; } @@ -605,12 +598,11 @@ Value listaddresstransactions(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from"); - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; + asset_amounts->Clear(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); vector fromaddresses; @@ -639,10 +631,9 @@ Value listaddresstransactions(const Array& params, bool fHelp) } - mc_Buffer *entity_rows; - entity_rows=new mc_Buffer; - entity_rows->Initialize(MC_TDB_ENTITY_KEY_SIZE,MC_TDB_ROW_SIZE,MC_BUF_MODE_DEFAULT); - + mc_Buffer *entity_rows=mc_gState->m_TmpBuffers->m_RpcEntityRows; + entity_rows->Clear(); + Array ret; if(mc_gState->m_WalletMode & MC_WMD_ADDRESS_TXS) { @@ -712,11 +703,6 @@ Value listaddresstransactions(const Array& params, bool fHelp) std::reverse(ret.begin(), ret.end()); // Return oldest to newest } - delete lpScript; - delete asset_amounts; - delete entity_rows; - - return ret; } @@ -750,12 +736,11 @@ Value getwallettransaction(const Array& params, bool fHelp) throw JSONRPCError(RPC_TX_NOT_FOUND, "Invalid or non-wallet transaction id"); } - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; + asset_amounts->Clear(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); Object entry; @@ -770,9 +755,6 @@ Value getwallettransaction(const Array& params, bool fHelp) entry=ListWalletTransactions(wtx,fLong,filter,NULL,asset_amounts,lpScript); } - delete lpScript; - delete asset_amounts; - if(entry.size() == 0) { throw JSONRPCError(RPC_TX_NOT_FOUND, "Wallet addresses with specified criteria are not involved in transaction"); @@ -809,12 +791,11 @@ Value getaddresstransaction(const Array& params, bool fHelp) } - mc_Buffer *asset_amounts; - asset_amounts=new mc_Buffer; - mc_InitABufferMap(asset_amounts); + mc_Buffer *asset_amounts=mc_gState->m_TmpBuffers->m_RpcABBuffer1; + asset_amounts->Clear(); - mc_Script *lpScript; - lpScript=new mc_Script; + mc_Script *lpScript=mc_gState->m_TmpBuffers->m_RpcScript3; + lpScript->Clear(); vector fromaddresses; @@ -859,9 +840,6 @@ Value getaddresstransaction(const Array& params, bool fHelp) throw JSONRPCError(RPC_TX_NOT_FOUND, "This transaction was not found for this address"); } - delete lpScript; - delete asset_amounts; - return entry; } diff --git a/src/rpc/rpcwalletutils.cpp b/src/rpc/rpcwalletutils.cpp index 3f93f3b0..bbef8f11 100644 --- a/src/rpc/rpcwalletutils.cpp +++ b/src/rpc/rpcwalletutils.cpp @@ -621,6 +621,7 @@ Object TxOutEntry(const CTxOut& TxOutIn,int vout,const CTxIn& TxIn,uint256 hash, Object txout_entry; Array permissions; + Array peroutputdata; isminetype fIsMine=ISMINE_NO; amounts->Clear(); // int iad=-1; @@ -719,6 +720,12 @@ Object TxOutEntry(const CTxOut& TxOutIn,int vout,const CTxIn& TxIn,uint256 hash, { txout_entry.push_back(Pair("permissions", permissions)); } + + peroutputdata=PerOutputDataEntries(txout,lpScript,hash,vout); + if(peroutputdata.size()) + { + txout_entry.push_back(Pair("data", peroutputdata)); + } } } diff --git a/src/structs/base58.cpp b/src/structs/base58.cpp index 9e117bc3..bbe4b3d8 100644 --- a/src/structs/base58.cpp +++ b/src/structs/base58.cpp @@ -262,81 +262,90 @@ std::string BurnAddress(const std::vector& vchVersion) char res[100]; int shift=nDataBytes / nVersionBytes; - vch.resize(nDataBytes + nVersionBytes + nHashBytes); + CKeyID kBurn; int p; - for(int i=2;i nDataBytes + nVersionBytes + nHashBytes) + if(*(uint160*)(mc_gState->m_BurnAddress) == 0) { - res[strlen(res)-1]=0x00; + vch.resize(nDataBytes + nVersionBytes + nHashBytes); + for(int i=2;i nDataBytes + nVersionBytes + nHashBytes) + { + res[strlen(res)-1]=0x00; + DecodeBase58(res,vch); + } - p=0; - while(p strlen(res)) + memset(&vch[p+2],0x00,vch.size()-p-2); + vch[p] = vchVersion[p / (shift+1)]; + vch[p+1] = 0x80; + strcpy(test,EncodeBase58(vch).c_str()); + if(strlen(test) != strlen(res)) { - res[strlen(res)+1]=0x00; - res[strlen(res)]='X'; - } - if(strlen(test) < strlen(res)) + if(strlen(test) > strlen(res)) + { + res[strlen(res)+1]=0x00; + res[strlen(res)]='X'; + } + if(strlen(test) < strlen(res)) + { + res[strlen(res)-1]=0x00; + } + } + int j=0; + while( (j<(int)strlen(res)) && (res[j] == test[j]) ) { - res[strlen(res)-1]=0x00; - } - } - int j=0; - while( (j<(int)strlen(res)) && (res[j] == test[j]) ) - { - j++; + j++; + } + int k=0; + while( (k<3) && (j<(int)strlen(res)) && ((vch[p] != vchVersion[p / (shift+1)]) || (k ==0))) + { + res[j]=test[j]; + DecodeBase58(res,vch); + k++; + j++; + } } - int k=0; - while( (k<3) && (j<(int)strlen(res)) && ((vch[p] != vchVersion[p / (shift+1)]) || (k ==0))) - { - res[j]=test[j]; - DecodeBase58(res,vch); - k++; - j++; - } } + p++; } - p++; - } - -// strcpy(test,EncodeBase58(vch).c_str()); - - - for(int i=0;i<(int)nVersionBytes;i++) - { - int size=shift; - if(i == (int)(nVersionBytes-1)) + + // strcpy(test,EncodeBase58(vch).c_str()); + + + for(int i=0;i<(int)nVersionBytes;i++) { - size=nDataBytes-i*shift; + int size=shift; + if(i == (int)(nVersionBytes-1)) + { + size=nDataBytes-i*shift; + } + memcpy(data+i*shift,&vch[i*(shift+1)+1],size); } - memcpy(data+i*shift,&vch[i*(shift+1)+1],size); + + memcpy(&kBurn,data,nDataBytes); + memcpy(mc_gState->m_BurnAddress,data,nDataBytes); + } + else + { + memcpy(&kBurn,mc_gState->m_BurnAddress,nDataBytes); } - - CKeyID kBurn; - memcpy(&kBurn,data,nDataBytes); CBitcoinAddress ba; ba.Set(kBurn,vchVersion); diff --git a/src/utils/declare.h b/src/utils/declare.h index e52b7394..ac6e15a0 100644 --- a/src/utils/declare.h +++ b/src/utils/declare.h @@ -243,6 +243,7 @@ void mc_SetDataDirArg(char *buf); void mc_ExpandDataDirParam(); void mc_CheckDataDirInConfFile(); void mc_AdjustStartAndCount(int *count,int *start,int size); +void* custom_get_blockchain_default(const char *param,int* size,void *param_in); int mc_TestScenario(char* scenario_file); diff --git a/src/utils/utilparse.cpp b/src/utils/utilparse.cpp index bbe01711..67da1063 100644 --- a/src/utils/utilparse.cpp +++ b/src/utils/utilparse.cpp @@ -27,6 +27,100 @@ const unsigned char* GetAddressIDPtr(const CTxDestination& address) return aptr; } +bool mc_ExtractOutputAssetQuantities(mc_Buffer *assets,string& reason,bool with_followons) +{ + int err; + uint32_t script_type=MC_SCR_ASSET_SCRIPT_TYPE_TRANSFER; + if(with_followons) + { + script_type |= MC_SCR_ASSET_SCRIPT_TYPE_FOLLOWON; + } + for (int e = 0; e < mc_gState->m_TmpScript->GetNumElements(); e++) + { + mc_gState->m_TmpScript->SetElement(e); + err=mc_gState->m_TmpScript->GetAssetQuantities(assets,script_type); + if((err != MC_ERR_NOERROR) && (err != MC_ERR_WRONG_SCRIPT)) + { + reason="Asset transfer script rejected - error in output transfer script"; + return false; + } + } + + return true; +} + +bool mc_VerifyAssetPermissions(mc_Buffer *assets, vector addressRets, int required_permissions, uint32_t permission, string& reason) +{ + mc_EntityDetails entity; + int asset_count=-1; + + for(int i=0;iGetCount();i++) + { + if(mc_gState->m_Assets->FindEntityByFullRef(&entity,assets->GetRow(i))) + { + if( entity.Permissions() & (MC_PTP_SEND | MC_PTP_RECEIVE) ) + { + if( (addressRets.size() != 1) || (required_permissions > 1) ) + { + reason="Sending restricted asset to non-standard and multisig addresses not allowed"; + return false; + } + if(assets->GetCount() > 1) + { + if(asset_count < 0) + { + asset_count=0; + for(int j=0;jGetCount();j++) + { + if(mc_GetABRefType(assets->GetRow(j)) != MC_AST_ASSET_REF_TYPE_SPECIAL) + { + asset_count++; + } + } + } + if(asset_count > 1) + { + if(permission == MC_PTP_SEND) + { + reason="One of multiple assets in input has per-asset permissions"; + } + if(permission == MC_PTP_RECEIVE) + { + reason="One of multiple assets in output has per-asset permissions"; + } + return false; + } + } + if(entity.Permissions() & permission) + { + int found=required_permissions; + for(int j=0;j<(int)addressRets.size();j++) + { + if(mc_gState->m_Permissions->GetPermission(entity.GetTxID(),GetAddressIDPtr(addressRets[j]),permission)) + { + found--; + } + } + if(found > 0) + { + if(permission == MC_PTP_SEND) + { + reason="One of the inputs doesn't have per-asset send permission"; + } + if(permission == MC_PTP_RECEIVE) + { + reason="One of the outputs doesn't have per-asset receive permission"; + } + return false; + } + } + } + } + } + + return true; +} + /* * Parses txout script into asset-quantity buffer diff --git a/src/utils/utilparse.h b/src/utils/utilparse.h index ba7dbd72..41c76e8e 100644 --- a/src/utils/utilparse.h +++ b/src/utils/utilparse.h @@ -20,6 +20,8 @@ void LogAssetTxOut(std::string message,uint256 hash,int index,unsigned char* ass bool AddressCanReceive(CTxDestination address); bool FindFollowOnsInScript(const CScript& script1,mc_Buffer *amounts,mc_Script *lpScript); int CheckRequiredPermissions(const CTxDestination& addressRet,int expected_allowed,std::map* mapSpecialEntity,std::string* strFailReason); +bool mc_VerifyAssetPermissions(mc_Buffer *assets, std::vector addressRets, int required_permissions, uint32_t permission, std::string& reason); +bool mc_ExtractOutputAssetQuantities(mc_Buffer *assets,std::string& reason,bool with_followons); diff --git a/src/utils/utilwrapper.cpp b/src/utils/utilwrapper.cpp index 4ea68afd..53223018 100644 --- a/src/utils/utilwrapper.cpp +++ b/src/utils/utilwrapper.cpp @@ -47,6 +47,7 @@ #include "structs/hash.h" #include "core/main.h" #include "net/net.h" +#include "custom/custom.h" #define MC_DCT_SEED_NODE_MAX_SIZE 32 @@ -77,6 +78,8 @@ void mc_Params::Parse(int argc, const char* const argv[],int exe_type) ParseParameters(argc,argv); mc_ExpandDataDirParam(); + custom_set_runtime_defaults(exe_type); + m_NumArguments=0; length=MC_DCT_SEED_NODE_MAX_SIZE+1; for (i = 1; i < argc; i++) @@ -715,6 +718,9 @@ int mc_BuildDescription(int build, char *desc) case 2: sprintf(desc+strlen(desc)," beta "); break; + case 7: + sprintf(desc+strlen(desc)," build "); + break; case 9: if(c[4] != 1)return MC_ERR_INVALID_PARAMETER_VALUE; break; @@ -729,6 +735,30 @@ int mc_BuildDescription(int build, char *desc) return MC_ERR_NOERROR; } + +int mc_MultichainParams::SetProtocolGlobals() +{ + if(mc_gState->m_Features->ShortTxIDInTx() == 0) + { + m_AssetRefSize=MC_AST_ASSET_REF_SIZE; + } + MCP_ALLOW_ARBITRARY_OUTPUTS=1; + if(mc_gState->m_Features->FixedDestinationExtraction() != 0) + { + int aao=mc_gState->m_NetworkParams->GetInt64Param("allowarbitraryoutputs"); + if(aao>=0) + { + MCP_ALLOW_ARBITRARY_OUTPUTS=aao; + } + } + if(mc_gState->m_Features->ParameterUpgrades()) + { + MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; + MAX_TX_SIGOPS = MAX_BLOCK_SIGOPS/5; + } + return MC_ERR_NOERROR; +} + int mc_MultichainParams::SetGlobals() { m_IsProtocolMultiChain=1; @@ -755,6 +785,7 @@ int mc_MultichainParams::SetGlobals() { MAX_SIZE *= 2; } + MIN_BLOCKS_BETWEEN_UPGRADES=(unsigned int)GetInt64Param("timingupgrademingap"); MAX_STANDARD_TX_SIZE=(unsigned int)GetInt64Param("maxstdtxsize"); MAX_SCRIPT_ELEMENT_SIZE=(unsigned int)GetInt64Param("maxstdelementsize"); COINBASE_MATURITY=(int)GetInt64Param("rewardspendabledelay"); @@ -767,12 +798,12 @@ int mc_MultichainParams::SetGlobals() CENT=0; MAX_MONEY=0; } - +/* if(mc_gState->m_Features->ShortTxIDInTx() == 0) { m_AssetRefSize=MC_AST_ASSET_REF_SIZE; } - +*/ MCP_MAX_STD_OP_RETURN_COUNT=mc_gState->m_NetworkParams->GetInt64Param("maxstdopreturnscount"); MCP_INITIAL_BLOCK_REWARD=mc_gState->m_NetworkParams->GetInt64Param("initialblockreward"); MCP_FIRST_BLOCK_REWARD=mc_gState->m_NetworkParams->GetInt64Param("firstblockreward"); @@ -784,6 +815,7 @@ int mc_MultichainParams::SetGlobals() MCP_ANYONE_CAN_RECEIVE=mc_gState->m_NetworkParams->GetInt64Param("anyonecanreceive"); MCP_ANYONE_CAN_ACTIVATE=mc_gState->m_NetworkParams->GetInt64Param("anyonecanactivate"); MCP_MINIMUM_PER_OUTPUT=mc_gState->m_NetworkParams->GetInt64Param("minimumperoutput"); +/* MCP_ALLOW_ARBITRARY_OUTPUTS=1; if(mc_gState->m_Features->FixedDestinationExtraction() != 0) { @@ -793,6 +825,7 @@ int mc_MultichainParams::SetGlobals() MCP_ALLOW_ARBITRARY_OUTPUTS=aao; } } + */ MCP_ALLOW_MULTISIG_OUTPUTS=mc_gState->m_NetworkParams->GetInt64Param("allowmultisigoutputs"); MCP_ALLOW_P2SH_OUTPUTS=mc_gState->m_NetworkParams->GetInt64Param("allowp2shoutputs"); MCP_WITH_NATIVE_CURRENCY=0; @@ -803,7 +836,7 @@ int mc_MultichainParams::SetGlobals() MCP_STD_OP_DROP_COUNT=mc_gState->m_NetworkParams->GetInt64Param("maxstdopdropscount"); MCP_STD_OP_DROP_SIZE=mc_gState->m_NetworkParams->GetInt64Param("maxstdopdropsize"); MCP_ANYONE_CAN_RECEIVE_EMPTY=mc_gState->m_NetworkParams->GetInt64Param("anyonecanreceiveempty"); - return MC_ERR_NOERROR; + return SetProtocolGlobals(); } diff --git a/src/version/version.cpp b/src/version/version.cpp index df793c07..ac342acf 100644 --- a/src/version/version.cpp +++ b/src/version/version.cpp @@ -3,12 +3,19 @@ #include "multichain/multichain.h" #include "version/version.h" - +#include "custom/custom.h" int mc_State::VersionInfo(int version) { - int this_build=20000101; - int this_protocol=20001; + int custom_version=custom_version_info(version); + if(custom_version != 0) + { + return custom_version; + } + + int this_build=20000102; + int this_protocol=20002; + if(version < 0) { return 0; @@ -25,6 +32,10 @@ int mc_State::VersionInfo(int version) return 10004; // first supported version case MULTICHAIN_VERSION_CODE_PROTOCOL_MIN_DOWNGRADE: return 10008; // cannot downgrade below this version + case MULTICHAIN_VERSION_CODE_PROTOCOL_MIN_NO_DOWNGRADE: + return 20002; // if we are on this version or above, downgrades are forbidden + case MULTICHAIN_VERSION_CODE_PROTOCOL_FOR_RELEVANCE: + return 0; // If not 0, defines relevant parameter set } return 0; } @@ -32,7 +43,7 @@ int mc_State::VersionInfo(int version) if(version < 10004)return -10000201; // last build supporting this version (negative) if(version < 10010)return -this_build; // supported by this version if(version < 20001)return 20001; // next version - if(version < 20002)return -this_build; // supported by this version + if(version < this_protocol+1)return -this_build; // supported by this version return VersionInfo(MULTICHAIN_VERSION_CODE_BUILD)-1; // Created by the following builds } @@ -102,7 +113,15 @@ int mc_State::MinProtocolDowngradeVersion() return VersionInfo(MULTICHAIN_VERSION_CODE_PROTOCOL_MIN_DOWNGRADE); } +int mc_State::MinProtocolForbiddenDowngradeVersion() +{ + return VersionInfo(MULTICHAIN_VERSION_CODE_PROTOCOL_MIN_NO_DOWNGRADE); +} +int mc_State::RelevantParamProtocolVersion() +{ + return VersionInfo(MULTICHAIN_VERSION_CODE_PROTOCOL_FOR_RELEVANCE); +} int mc_State::GetWalletDBVersion() { diff --git a/src/version/version.h b/src/version/version.h index 70b5e9a1..06886129 100644 --- a/src/version/version.h +++ b/src/version/version.h @@ -53,8 +53,10 @@ #define MULTICHAIN_VERSION_CODE_PROTOCOL_THIS 0 #define MULTICHAIN_VERSION_CODE_PROTOCOL_MIN 1 #define MULTICHAIN_VERSION_CODE_PROTOCOL_MIN_DOWNGRADE 2 +#define MULTICHAIN_VERSION_CODE_PROTOCOL_MIN_NO_DOWNGRADE 3 +#define MULTICHAIN_VERSION_CODE_PROTOCOL_FOR_RELEVANCE 4 #define MULTICHAIN_VERSION_CODE_BUILD 16 -#define MULTICHAIN_VERSION_CODE_MIN_VALID 10000 +#define MULTICHAIN_VERSION_CODE_MIN_VALID 1000 #endif /* MULTICHAINVERSION_H */ diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b377ce6a..cce28d7b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1944,7 +1944,8 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const /** * populate vCoins with vector of available COutputs. */ -void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fOnlyUnlocked, bool fOnlyCoinsNoTxs, uint160 addr, uint32_t flags) const +void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fOnlyUnlocked, bool fOnlyCoinsNoTxs, + uint160 addr, const set* addresses, uint32_t flags) const { vCoins.clear(); @@ -1960,10 +1961,12 @@ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const for (map::const_iterator it = pwalletTxsMain->m_UTXOs[0].begin(); it != pwalletTxsMain->m_UTXOs[0].end(); ++it) { const mc_Coin& coin = it->second; - if((addr == 0) || (addr == coin.m_EntityID)) + if( ( (addresses == NULL) && (addr == 0) ) || + (addr == coin.m_EntityID) || + ( (addresses != NULL) && (addresses->count(coin.m_EntityID) != 0)) ) { isminetype mine; - bool is_p2sh=false;; + bool is_p2sh=false; if(coin.m_EntityType) { if(coin.m_Flags & MC_TFL_IS_SPENDABLE) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 1e420fca..7c0dddb0 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -179,6 +179,7 @@ class CAssetGroupTree int nMaxAssetsPerGroup; int nOptimalGroupCount; int nMode; + int nSingleAssetGroupCount; void Clear(); void Destroy(); @@ -187,6 +188,7 @@ class CAssetGroupTree int *lpTmpGroupBuffer; CAssetGroup *FindAndShiftBestGroup(int assets); + CAssetGroup *AddSingleAssetGroup(unsigned char *assetRef); public: @@ -384,7 +386,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface /* MCHN START */ // void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL) const; void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fOnlyUnlocked=true, - bool fOnlyCoinsNoTxs=false, uint160 addr=0, uint32_t flags=MC_CSF_ALLOW_SPENDABLE_P2SH) const; + bool fOnlyCoinsNoTxs=false, uint160 addr=0, const std::set* addresses=NULL, uint32_t flags=MC_CSF_ALLOW_SPENDABLE_P2SH) const; /* MCHN END */ bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet) const; diff --git a/src/wallet/walletcoins.cpp b/src/wallet/walletcoins.cpp index cbfd9ba8..9636ae6e 100644 --- a/src/wallet/walletcoins.cpp +++ b/src/wallet/walletcoins.cpp @@ -11,6 +11,7 @@ #include "script/sign.h" #include "utils/utilmoneystr.h" #include "rpc/rpcprotocol.h" +#include "custom/custom.h" extern mc_WalletTxs* pwalletTxsMain; @@ -25,6 +26,7 @@ void CAssetGroupTree::Clear() nMaxAssetsPerGroup=0; nOptimalGroupCount=0; nMode=0; + nSingleAssetGroupCount=0; lpAssets=NULL; lpAssetGroups=NULL; lpTmpGroupBuffer=NULL; @@ -52,10 +54,12 @@ void CAssetGroupTree::Dump() CAssetGroup *thisGroup; int *aptr; unsigned char *assetrefbin; - int i,j; + int i,j,s; - if(debug_print)printf("Asset Grouping. Group Size: %d. Group Count: %d\n",nAssetsPerGroup,lpAssetGroups->GetCount()-1); - if(fDebug)LogPrint("mchn","mchn: Asset Grouping. Group Size: %d. Group Count: %d\n",nAssetsPerGroup,lpAssetGroups->GetCount()-1); + if(debug_print)printf("Asset Grouping. Assets: %d. Group Size: %d. Group Count: %d. Single-Asset Groups: %d.\n", + lpAssets->GetCount(),nAssetsPerGroup,lpAssetGroups->GetCount()-1,nSingleAssetGroupCount); + if(fDebug)LogPrint("mchn","mchn: Asset Grouping. Assets: %d. Group Size: %d. Group Count: %d. Single-Asset Groups: %d.\n", + lpAssets->GetCount(),nAssetsPerGroup,lpAssetGroups->GetCount()-1,nSingleAssetGroupCount); for(i=1;iGetCount();i++) { thisGroup=(CAssetGroup*)lpAssetGroups->GetRow(i); @@ -63,7 +67,12 @@ void CAssetGroupTree::Dump() { printf("Group: %4d. Asset Count: %d\n",i,thisGroup->nSize); aptr=(int*)(lpAssetGroups->GetRow(i)+sizeof(CAssetGroup)); - for(j=0;jnSize;j++) + s=thisGroup->nSize; + if(s<0) + { + s=1; + } + for(j=0;jGetRow(aptr[j]); @@ -102,8 +111,7 @@ int CAssetGroupTree::Resize(int newAssets) CAssetGroup *thisGroup; n=nAssetsPerGroup; - - while(nOptimalGroupCount*n < lpAssets->GetCount()+newAssets) + while(nOptimalGroupCount*n < lpAssets->GetCount()+newAssets-nSingleAssetGroupCount) { n*=2; } @@ -276,7 +284,6 @@ CAssetGroup *CAssetGroupTree::FindAndShiftBestGroup(int assets) thisGroup->nNextGroup=0; // The group is full } - return thisGroup; } @@ -297,13 +304,14 @@ int CAssetGroupTree::GetGroup(mc_Buffer* assets, int addIfNeeded) return -1; } - int group_id,last_asset_count,new_asset_count; + int group_id,last_asset_count,new_asset_count,only_asset; int i,g; int *iptr; int *aptr; unsigned char *assetRef; CAssetGroup *thisGroup; + only_asset=-1; group_id=-2; // No assets in this buffer last_asset_count=lpAssets->GetCount(); for(i=0;iGetCount();i++) @@ -314,6 +322,14 @@ int CAssetGroupTree::GetGroup(mc_Buffer* assets, int addIfNeeded) (mc_GetABRefType(assetRef) != MC_AST_ASSET_REF_TYPE_GENESIS) ) // if(mc_GetLE(assetRef,4) > 0) { + if(only_asset == -1) + { + only_asset=i; + } + else + { + only_asset=-2; // More than one asset + } g=GetGroup(assetRef,0); if(g>0) { @@ -361,7 +377,17 @@ int CAssetGroupTree::GetGroup(mc_Buffer* assets, int addIfNeeded) thisGroup=NULL; - Resize(new_asset_count - last_asset_count); + if(only_asset >= 0) // Assets which cannot be combined with other + { + thisGroup=AddSingleAssetGroup(assets->GetRow(only_asset)); + if(thisGroup) + { + return thisGroup->nThisGroup; + } + } + +// Resize(new_asset_count - last_asset_count); + Resize(0); // Assets already added if(group_id > 0) // There are old assets, so we know what should be group id { @@ -426,6 +452,45 @@ int CAssetGroupTree::GetGroup(mc_Buffer* assets, int addIfNeeded) return 0; } + +/* + * Returns group id of the asset + * Adds single assets + */ + +CAssetGroup *CAssetGroupTree::AddSingleAssetGroup(unsigned char *assetRef) +{ + mc_EntityDetails entity; + int group_id,asset_id; + int *aptr; + + if(mc_gState->m_Assets->FindEntityByFullRef(&entity,assetRef)) + { + if( entity.Permissions() & (MC_PTP_SEND | MC_PTP_RECEIVE) ) + { + asset_id=lpAssets->GetCount()-1; + group_id=lpAssetGroups->GetCount(); + CAssetGroup assetGroup; + assetGroup.nThisGroup=group_id; + assetGroup.nNextGroup=0; + assetGroup.nSize=-1; + memset(lpTmpGroupBuffer,0,nAssetsPerGroup*sizeof(int)); + if(lpAssetGroups->Add(&assetGroup,lpTmpGroupBuffer)) + { + return NULL; + } + *(int*)(lpAssets->GetRow(asset_id)+MC_AST_ASSET_QUANTITY_OFFSET)=group_id; + aptr=(int*)(lpAssetGroups->GetRow(group_id)+sizeof(CAssetGroup)); + aptr[0]=asset_id; + nSingleAssetGroupCount++; + return (CAssetGroup *)(lpAssetGroups->GetRow(group_id)); + } + } + + return NULL; +} + + /* * Returns group id of the asset * Adds to the groups if addIfNeeded==1 @@ -605,7 +670,7 @@ void AvalableCoinsForAddress(CWallet *lpWallet,vector& vCoins, const CC } } - lpWallet->AvailableCoins(vCoins, true, coinControl,true,true,addr,flags); + lpWallet->AvailableCoins(vCoins, true, coinControl,true,true,addr,NULL,flags); this_time=mc_TimeNowAsDouble(); if(fDebug)LogPrint("mcperf","mcperf: AvailableCoins: Time: %8.6f \n", this_time-last_time); last_time=this_time; @@ -751,7 +816,8 @@ bool FindRelevantCoins(CWallet *lpWallet, out_i=out.i; tmp_amounts->Clear(); - if(ParseMultichainTxOutToBuffer(hash,txout,tmp_amounts,lpScript,&allowed,&required,mapSpecialEntity,strError)) + if(custom_good_for_coin_selection(txout.scriptPubKey) && + ParseMultichainTxOutToBuffer(hash,txout,tmp_amounts,lpScript,&allowed,&required,mapSpecialEntity,strError)) { // All coins are taken, possible future optimization /* @@ -795,8 +861,30 @@ bool FindRelevantCoins(CWallet *lpWallet, } if(is_relevant) { - if(allowed & MC_PTP_SEND) + if(mc_gState->m_Features->PerAssetPermissions()) { + CTxDestination addressRet; + + if(allowed & MC_PTP_SEND) + { + if(ExtractDestinationScriptValid(txout.scriptPubKey, addressRet)) + { + string strPerAssetFailReason; + + vector addressRets; + addressRets.push_back(addressRet); + + if(!mc_VerifyAssetPermissions(tmp_amounts,addressRets,1,MC_PTP_SEND,strPerAssetFailReason) || + !mc_VerifyAssetPermissions(tmp_amounts,addressRets,1,MC_PTP_RECEIVE,strPerAssetFailReason)) + { + allowed -= MC_PTP_SEND; + } + } + } + } + + if(allowed & MC_PTP_SEND) + { if(!InsertCoinIntoMatrix(coin_id,hash,out_i,tmp_amounts,out_amounts,in_amounts,in_map,in_row,in_size,in_special_row,pure_native)) { strFailReason=_("Internal error: Cannot update input amount matrix"); @@ -856,7 +944,6 @@ bool FindCoinsToCombine(CWallet *lpWallet, int full_count,this_count,pure_native_count; CAmount total_native; int total_native_hit; - vector > active_groups; // Groups found in UTXOs group_count=lpWallet->lpAssetGroups->GroupCount(); @@ -881,7 +968,8 @@ bool FindCoinsToCombine(CWallet *lpWallet, uint256 hash=out.GetHashAndTxOut(txout); out_i=out.i; tmp_amounts->Clear(); - if(ParseMultichainTxOutToBuffer(hash,txout,tmp_amounts,lpScript,&allowed,&required,strError)) + if(custom_good_for_coin_selection(txout.scriptPubKey) && + ParseMultichainTxOutToBuffer(hash,txout,tmp_amounts,lpScript,&allowed,&required,strError)) { if( (required & MC_PTP_ISSUE) == 0 ) // Ignore txouts containing unconfirmed geneses { @@ -991,7 +1079,8 @@ bool FindCoinsToCombine(CWallet *lpWallet, uint256 hash=out.GetHashAndTxOut(txout); out_i=out.i; tmp_amounts->Clear(); - if(ParseMultichainTxOutToBuffer(hash,txout,tmp_amounts,lpScript,&allowed,&required,strError)) + if(custom_good_for_coin_selection(txout.scriptPubKey) && + ParseMultichainTxOutToBuffer(hash,txout,tmp_amounts,lpScript,&allowed,&required,strError)) { if( (required & MC_PTP_ISSUE) == 0 ) // Ignore txouts containing unconfirmed geneses { @@ -1835,6 +1924,139 @@ CAmount BuildAssetTransaction(CWallet *lpWallet, return 0; } +bool CheckOutputPermissions(const vector >& vecSend,mc_Buffer *tmp_amounts,std::string& strFailReason,int *eErrorCode) +{ + int receive_required; + int64_t quantity; + int err; + bool fIsMaybePurePermission,fIsGenesis; + + BOOST_FOREACH (const PAIRTYPE(CScript, CAmount)& s, vecSend) + { + txnouttype typeRet; + int nRequiredRet; + vector addressRets; + if(!ExtractDestinations(s.first,typeRet,addressRets,nRequiredRet)) + { + if(typeRet != TX_NULL_DATA) + { + strFailReason="Non-standard outputs are not supported in coin selection"; + *eErrorCode=RPC_INTERNAL_ERROR; + return false; + } + } + if(addressRets.size()>0) + { + receive_required=addressRets.size(); + if(typeRet == TX_MULTISIG) + { + receive_required-=nRequiredRet; + receive_required+=1; + if(receive_required>(int)addressRets.size()) + { + receive_required=addressRets.size(); + } + } + + CScript::const_iterator pc1 = s.first.begin(); + + mc_gState->m_TmpScript->Clear(); + mc_gState->m_TmpScript->SetScript((unsigned char*)(&pc1[0]),(size_t)(s.first.end()-pc1),MC_SCR_TYPE_SCRIPTPUBKEY); + + tmp_amounts->Clear(); + if(!mc_ExtractOutputAssetQuantities(tmp_amounts,strFailReason,true)) + { + *eErrorCode=RPC_INTERNAL_ERROR; + return false; + } + if(!mc_VerifyAssetPermissions(tmp_amounts,addressRets,receive_required,MC_PTP_RECEIVE,strFailReason)) + { + *eErrorCode=RPC_NOT_ALLOWED; + return false; + } + + fIsMaybePurePermission=true; + fIsGenesis=false; + for (int e = 0; e < mc_gState->m_TmpScript->GetNumElements(); e++) + { + mc_gState->m_TmpScript->SetElement(e); + err=mc_gState->m_TmpScript->GetAssetGenesis(&quantity); + if(err == 0) + { + fIsGenesis=true; + fIsMaybePurePermission=false; + } + err=mc_gState->m_TmpScript->GetRawData(NULL,NULL); + if(err == 0) + { + fIsMaybePurePermission=false; + } + } + + if(tmp_amounts->GetCount()) + { + if(fIsGenesis) + { + strFailReason="Asset issuance and asset transfer are not allowed in one output"; + *eErrorCode=RPC_NOT_ALLOWED; + return false; + } + fIsMaybePurePermission=false; + } + + if(s.second > 0) + { + fIsMaybePurePermission=false; + } + + if(!fIsMaybePurePermission) + + { + if( (s.second > 0) || + (tmp_amounts->GetCount() > 0) || + (mc_gState->m_Features->AnyoneCanReceiveEmpty() == 0) ) + { + for(int a=0;a<(int)addressRets.size();a++) + { + CKeyID *lpKeyID=boost::get (&addressRets[a]); + CScriptID *lpScriptID=boost::get (&addressRets[a]); + if((lpKeyID == NULL) && (lpScriptID == NULL)) + { + strFailReason="Wrong destination type"; + *eErrorCode=RPC_INTERNAL_ERROR; + return false; + } + unsigned char* ptr=NULL; + if(lpKeyID != NULL) + { + ptr=(unsigned char*)(lpKeyID); + } + else + { + ptr=(unsigned char*)(lpScriptID); + } + + bool fCanReceive=mc_gState->m_Permissions->CanReceive(NULL,ptr); + + if(fCanReceive) + { + receive_required--; + } + } + if(receive_required>0) + { + strFailReason="One of the outputs doesn't have receive permission"; + *eErrorCode=RPC_INSUFFICIENT_PERMISSIONS; + return false; + } + } + } + } + } + + return true; +} + bool CreateAssetGroupingTransaction(CWallet *lpWallet, const vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl, const set* addresses,int min_conf,int min_inputs,int max_inputs,const vector* lpCoinsToUse,uint32_t flags,int *eErrorCode) @@ -1918,6 +2140,11 @@ bool CreateAssetGroupingTransaction(CWallet *lpWallet, const vectorsize() != 1) ) { @@ -2486,7 +2713,7 @@ bool CWallet::InitializeUnspentList() int max_assets_per_group=assets_per_opdrop*MCP_STD_OP_DROP_COUNT; lpAssetGroups->Initialize(1,max_assets_per_group,32,1); - + vector vCoins; mc_Buffer *tmp_amounts; @@ -2510,8 +2737,22 @@ bool CWallet::InitializeUnspentList() ParseMultichainTxOutToBuffer(hash,txout,tmp_amounts,lpScript,NULL,NULL,strError); } asset_count=tmp_amounts->GetCount(); - if(asset_count) // Resize asset grouping to prevent crazy autocombine on - // already autocombined with higher assets-per-group setting + if(mc_gState->m_Features->PerAssetPermissions()) + { + mc_EntityDetails entity; + for(int i=0;iGetCount();i++) + { + if(mc_gState->m_Assets->FindEntityByFullRef(&entity,tmp_amounts->GetRow(i))) + { + if( entity.Permissions() & (MC_PTP_SEND | MC_PTP_RECEIVE) ) + { + asset_count--; + } + } + } + } + if(asset_count > 0) // Resize asset grouping to prevent crazy autocombine on + // already autocombined with higher assets-per-group setting { lpAssetGroups->Resize(asset_count); } diff --git a/src/wallet/wallettxs.cpp b/src/wallet/wallettxs.cpp index cb358288..fd600e84 100644 --- a/src/wallet/wallettxs.cpp +++ b/src/wallet/wallettxs.cpp @@ -25,7 +25,8 @@ using namespace std; void WalletTxNotify(mc_TxImport *imp,const CWalletTx& tx,int block,bool fFound,uint256 block_hash) { - std::string strNotifyCmd = GetArg("-walletnotify", ""); +// std::string strNotifyCmd = GetArg("-walletnotify", ""); + std::string strNotifyCmd = GetArg("-walletnotify", fFound ? "" : GetArg("-walletnotifynew", "")); if ( strNotifyCmd.empty() ) { return; @@ -816,6 +817,7 @@ int mc_WalletTxs::RollBack(mc_TxImport *import,int block) mc_Buffer *lpSubKeyEntRowBuffer; bool fInBlocks; std::vector txouts; + std::vector removed_coinbases; if((m_Mode & MC_WMD_TXS) == 0) { @@ -1069,6 +1071,10 @@ int mc_WalletTxs::RollBack(mc_TxImport *import,int block) } } if(fDebug)LogPrint("wallet","wtxs: Removing tx %s, block %d, flags: %08X, import %d\n",hash.ToString().c_str(),entrow->m_Block,entrow->m_Flags,imp->m_ImportID); + if(wtx.IsCoinBase()) + { + removed_coinbases.push_back(hash); + } } } else @@ -1120,6 +1126,11 @@ int mc_WalletTxs::RollBack(mc_TxImport *import,int block) if(err == MC_ERR_NOERROR) { err=m_Database->RollBack(import,block); // Database rollback + for(i=0;i<(int)removed_coinbases.size();i++) + { + uint256 hash=removed_coinbases[i]; + m_Database->SaveTxFlag((unsigned char*)&hash,MC_TFL_INVALID,1); + } } if(err) { @@ -2610,7 +2621,7 @@ int mc_WalletTxs::AddTx(mc_TxImport *import,const CWalletTx& tx,int block,CDiskT } fAlreadyInTheWalletForNotify=false; - if(!GetArg("-walletnotify", "").empty()) + if(!GetArg("-walletnotify", "").empty() || !GetArg("-walletnotifynew", "").empty()) { mc_TxDefRow StoredTxDef; if(m_Database->GetTx(&StoredTxDef,(unsigned char*)&hash) == 0)