github.com/aidoskuneen/adk-node@v0.0.0-20220315131952-2e32567cb7f4/adkgo-GENESIS/contracts/ADKTransactions.sol (about)

     1  // SPDX-License-Identifier: GPL-3.0
     2  pragma solidity >0.8.4;
     3  
     4  // ADKTransactions Contract for ADKGO - requires CURL Extended Version of EVM/AVM
     5  //import "contracts/AGSClaim.sol";
     6  
     7  interface ADKTokenInterface {
     8      function AZ9balanceOf(string memory _adkAddr) external view returns (uint256 balance);
     9      function meshTransaction(string memory _meshaddr, int256 _value) external;
    10      function AZ9_TO_ADDR (string memory adkString) external pure returns(address);
    11  }
    12  
    13  // Implementation of the ADK Mesh Structure and Signature Validation Genesis Contract
    14  
    15  contract ADKTransactions {
    16  
    17      address public ADKTokenAddress; // Holds the address of the ADK Genesis Contract managing balances
    18      address public adkgo_genesis_address; // Contract genesis address
    19  
    20      constructor(
    21              address _genesis_account,
    22              address _ADKTokenContract
    23          ){
    24          // DEPLOY MAIN ADK CONTRACT
    25          ADKTokenAddress = _ADKTokenContract; // The ADK Token Contract
    26          adkgo_genesis_address = _genesis_account;
    27          ClientProofOfWorkRequirement = 15; // PoW effort required (must be multiple of 3)
    28          createGenesisTransaction();
    29      }
    30  
    31      // Create the initial genesis transaction, for all "9" address
    32      bool genesisCreated = false;
    33      function createGenesisTransaction() internal {
    34          // BEGIN Create genesis transaction
    35          require(!genesisCreated);
    36          genesisCreated = true;
    37          baseTransactionHash = "999999999999999999999999999999999999999999999999999999999999999999999999999999999";
    38          bytes memory baseT = new bytes(2673);
    39          for (uint i = 0; i < 2673; i++)
    40              baseT[i] = 0x39; // 0x39 = "9"
    41          baseTransaction = string(baseT); // thats now 2673 "9" = the Genesis transaction
    42          bytes32 transactionHashSha3 = keccak256(bytes(baseTransactionHash));
    43          transactions[transactionHashSha3] = baseTransaction;
    44          transaction_hashes[transactionHashSha3] = baseTransactionHash;
    45          meshTip = transactionHashSha3;
    46          transaction_trunk[transactionHashSha3] = transactionHashSha3;
    47          transaction_branch[transactionHashSha3] = transactionHashSha3;
    48          tx_count = 0;
    49          // END Create genesis transaction
    50      }
    51  
    52  
    53      mapping(bytes32 => string) public transactions; // all stored and confirmed transactions, indexed by their keccak hash
    54      mapping(bytes32 => string) public transaction_hashes; // all stored and confirmed transaction hashes, indexed by their keccak hash
    55  
    56      mapping(bytes32 => bool) public spent_addresses; // store addresses that have been spent from before. Can be used by clients to avoid sending to already used AZ9 addresses
    57  
    58      mapping(bytes32 => bytes32) public transactionhash_by_address; // stores sha3(transactionhash) by sha3(address), increment by 1 for each further transaction
    59                                                                     // replaces events as this is faster
    60      mapping(bytes32 => bytes32) public transactionhash_by_bundle;  // stores sha3(transactionhash) by sha3(bundle), increment by 1 for each further transaction
    61                                                                     // replaces events as this is faster
    62      mapping(bytes32 => uint32) public transactionhash_by_address_count;
    63      mapping(bytes32 => uint32) public transactionhash_by_bundle_count;
    64      
    65      mapping(uint256 => bytes32) public transaction_indexed_by_seq; // transaction sha3 indexed by their sequence/occurence
    66      mapping(bytes32 => uint256) public transaction_index; // transaction sha3 indexed by their sequence/occurence (reversed)
    67      uint256 public tx_count;
    68      
    69      // mesh structure
    70      string baseTransaction; // always all '9'
    71      string baseTransactionHash; // always all '9'
    72  
    73      mapping(bytes32 => bytes32) public transaction_trunk; // transactions info indexed by their keccak hash: trunk
    74      mapping(bytes32 => bytes32) public transaction_branch; // transactions info indexed by their keccak hash: branch
    75  
    76      bytes32 public meshTip; // the highest tip in the mesh
    77  
    78      uint256 public ClientProofOfWorkRequirement;
    79  
    80      // mesh indexing
    81      event transactions_by_bundle(bytes32 indexed bundleSHA3, bytes32 transactionSHA3); // logs transactions per bundle, tighly packed bytes32 keccak hashes of transactions
    82      event transactions_by_address(bytes32 indexed addressSHA3, bytes32 transactionSHA3); // logs transactions per address, tighly packed bytes32 keccak hashes of transactions
    83  
    84      // testBundleBalances are used to ensure that a transaction bundle does not cause any balances to go negative
    85      mapping(string => int256) private testBundleBalances; // before and after balance computations these are always 0;
    86       // testBundleBalances are used to ensure that a transaction bundle does not cause any balances to go negative
    87      mapping(uint256 => bytes32) private tmpSha3TransactionHashes; // temp array to hold current transaction hashes for structure check;
    88  
    89      // Get AZ9 balance wrapper function, fetches ADK balance from ADK Token Genesis contract
    90      function GetAZ9balanceOf(string memory _adkAddr) public view returns (uint256 balance){
    91          return  ADKTokenInterface(ADKTokenAddress).AZ9balanceOf(_adkAddr); // pass through
    92      }
    93  
    94  
    95      // PostTransactions: This is the main entry point used by clients to submit full transaction bundles.
    96      //                   It requires an entire bundle of a transaction, in the correct sequence, and with PoW completed
    97  
    98      // This function checks for the minimum POW, valid signatures, valid bundle hashes, sufficient balances
    99  
   100      // If all is ok, the transfer is executed as soon as it is mined (PoA/PoS - depending on the stage)
   101  
   102      bool mutex_PostTransactions = false; // mutex to prevent reentry
   103      function PostTransactions(string memory transactiondata) public mod_requireAZ9(transactiondata) returns(string memory) {
   104  
   105          // // Check mutex
   106          // require (!mutex_PostTransactions,"reentry prevented!");
   107          // mutex_PostTransactions = true; // prevent reentry exploits
   108  
   109          // bytes memory b_trytes = bytes(transactiondata); // Load transaction AZ9 string into bytes
   110          // require(b_trytes.length % 2673 == 0 && b_trytes.length > 0 ,"Invalid transaction(s) length");
   111          // uint16 cnt_transactions = uint16(b_trytes.length / 2673);  // count number of included individual transactions
   112  
   113          // bytes memory all_essential_parts = new bytes(cnt_transactions*162); // each essential is 162 char long, all essentials make the bundle hash
   114  
   115          // int totalBundleValue = 0; // has to be 0  (i.e. input and output values have to net 0)
   116          // int lastIndex = -1;         // initialize
   117          // string memory s_bundle = ""; // initialize
   118          // // process each transaction one by one
   119          // for (uint32 transaction_idx = 0; transaction_idx < cnt_transactions; transaction_idx++){
   120  
   121          //     TransactionInfoStruct memory tinfo; // will hold all key transaction data (also used to avoid stack errors due to too many variables)
   122          //     tinfo.offset = transaction_idx * 2673; // offset of each transaction in the entire string
   123  
   124          //     tinfo.data = substring(transactiondata,tinfo.offset , tinfo.offset + 2673); // extract the current transaction
   125          //     tinfo.trans_hash = bytes(CurlHashOP(tinfo.data));  // Call the Hash Operation in order to get the transaction hash
   126  
   127          //     // Validate PoW
   128          //     // force the last X digits to be 0 (client POW); //
   129  
   130          //     for ( uint checkIdx = 0; checkIdx < ClientProofOfWorkRequirement/3; checkIdx ++ ){
   131          //         uint byte_index = 80 - checkIdx;  // 80,79,78,.. integer division to get byte position to check
   132          //                                               // note we only check full bytes, not by trits. So difficulty can be e.g. ... , 9, 12, 15, 18, 21 ...
   133          //         require(tinfo.trans_hash[byte_index] == 0x39, // 0x39 = "9",
   134          //                 "TRANSACTION POW NOT COMPLETED"
   135          //                 );
   136          //     }
   137  
   138          //     // Transaction Hash Handling
   139          //     tinfo.transactionSHA3 = keccak256(tinfo.trans_hash); // get keccak hash of transaction hash for indexing
   140          //     require(bytes(transactions[tinfo.transactionSHA3]).length == 0 ,"TRANSACTION ALREADY PROCESSED");
   141          //     transactions[tinfo.transactionSHA3] = string(tinfo.data); // store transaction
   142          //     transaction_hashes[tinfo.transactionSHA3] = string(tinfo.trans_hash); // store transaction Hash
   143          //     tx_count++;
   144          //     transaction_indexed_by_seq[tx_count] = tinfo.transactionSHA3;
   145          //     transaction_index[tinfo.transactionSHA3] = tx_count;
   146  
   147          //      // Trunk + Branch Handling
   148          //     // Build mesh structure: trunk and branch, just store for now, check later
   149          //     transaction_trunk[tinfo.transactionSHA3] = keccak256(subbytes(b_trytes,uint32(tinfo.offset+2430),uint32(tinfo.offset+2430+81)));
   150          //     transaction_branch[tinfo.transactionSHA3] = keccak256(subbytes(b_trytes,uint32(tinfo.offset+2511),uint32(tinfo.offset+2511+81)));
   151  
   152          //     tmpSha3TransactionHashes[transaction_idx] = tinfo.transactionSHA3; // store for later consistency check
   153  
   154          //     // record highest mesh tip
   155          //     if (transaction_idx ==0) {
   156          //         meshTip = tinfo.transactionSHA3; // becomes highest mesh tip
   157          //     }
   158  
   159          //     // Bundle Hash: recurd current transaction essential parts for later bundle hash generation
   160  
   161          //     for (uint16 idx = 0; idx < 162; idx++){ // get essential parts for bunlde hash calculation
   162          //         all_essential_parts[(transaction_idx*162) + idx] = b_trytes[tinfo.offset + 2187 + idx];
   163          //     }
   164  
   165          //     // Transaction Address Value Handling
   166  
   167          //     tinfo.s_address = substring(tinfo.data,2187,2268); // get current transaction address
   168          //     testBundleBalances[tinfo.s_address] = 0; // set ot 0 for now, we will use this later to check sufficient balance availability
   169  
   170          //     // Cummulative bundle value calculation up to current transaction (must be 0 after all transactions loaded, i.e. input total = output total)
   171          //     tinfo.transactionValue = TryteToIntValue(subbytes(b_trytes,tinfo.offset+2268,tinfo.offset+2279));
   172          //     totalBundleValue += tinfo.transactionValue;
   173  
   174          //     // just some additional checks, can never be too careful
   175          //     require(tinfo.transactionValue >= -2500000000000000,"transaction value too low");
   176          //     require(tinfo.transactionValue <= 2500000000000000,"transaction value too high");
   177          //     require(totalBundleValue >= -2500000000000000,"bundle cummulative transaction value too low");
   178          //     require(totalBundleValue <= 2500000000000000,"bundle cummulative transaction value too high");
   179  
   180          //     // Validate transaction index - current and total index (ensure transaction is in correct sequence)
   181  
   182          //     // check transaction indices
   183          //     tinfo.b_lastIndex = subbytes(b_trytes,tinfo.offset+2340,tinfo.offset+2349);
   184          //     tinfo.b_bundle = subbytes(b_trytes,tinfo.offset+2349,tinfo.offset+2349+81);
   185  
   186          //     if (transaction_idx==0){
   187          //         s_bundle = string(tinfo.b_bundle);
   188          //         lastIndex = TryteToIntValue(tinfo.b_lastIndex);
   189          //     }
   190          //     else {
   191          //         require(TryteToIntValue(tinfo.b_lastIndex) == lastIndex,"lastIndex not consistent"); // last index has to be the same across all transactions
   192          //         require(compareStrings(s_bundle, string(tinfo.b_bundle)),"bundle not consistent"); // bundle has to be the same across all transactions
   193          //     }
   194  
   195          //     tinfo.b_currentIndex = subbytes(b_trytes,tinfo.offset+2331,tinfo.offset+2340);
   196          //     tinfo.currentIndex = TryteToIntValue(tinfo.b_currentIndex);
   197  
   198          //     require(transaction_idx == uint(tinfo.currentIndex), "transaction sequence invalid"); // transaction number has to match index
   199  
   200          //     if (transaction_idx == cnt_transactions - 1){
   201          //         require(transaction_idx == uint(lastIndex), "last transaction != lastIndex"); // transaction number has to match lastIndex for last transaction
   202          //     }
   203  
   204          //     // SIGNATURE VALIDATIONS FOR SPENDING TRANSACTIONS ///////////////////////
   205          //     // Check signature for spending transactions
   206  
   207          //     if (tinfo.transactionValue < 0){ // only need to check signatures for spending transactions
   208  
   209          //         // Note: adkgo requires Signature Level 2, meaning the signature is spread across 2 transactions
   210  
   211          //         // the last transaction can't be a spending transaction, as each spending transaction has one more 0 value signature transaction
   212          //         require (transaction_idx < uint(lastIndex),"missing 2nd signature"); // there must be at least one more transaction
   213  
   214          //         tinfo.sig2_address = substring(transactiondata,tinfo.offset+2673+2187,tinfo.offset+2673+2268);
   215          //         tinfo.sig2_value = TryteToIntValue(subbytes(b_trytes,tinfo.offset+2673+2268,tinfo.offset+2673+2279));
   216  
   217          //         require (compareStrings(tinfo.s_address, tinfo.sig2_address),"2nd signature has invalid address"); // there must be at least one more transaction
   218          //         require (tinfo.sig2_value==0,"2nd signature is not 0 value");
   219  
   220          //         tinfo.sigA = substring(transactiondata,tinfo.offset+0,tinfo.offset+2187);
   221          //         tinfo.sigB = substring(transactiondata,tinfo.offset+2673,tinfo.offset+2673+2187);
   222  
   223          //         // Validate Signature
   224          //         require( CurlValidateSignature(tinfo.s_address,
   225          //                                       concat(tinfo.sigA,tinfo.sigB),
   226          //                                        s_bundle),
   227          //                                        "INVALID SIGNATURE");
   228          //         //
   229          //         spent_addresses[keccak256(bytes(tinfo.sig2_address))] = true;
   230          //     }
   231  
   232          //     emit EventLogInt(tinfo.s_address, tinfo.transactionValue);
   233  
   234          //     //log for faster retrieval later, also used by "find_transactions"
   235          //     bytes32 bundleSHA3 = keccak256(tinfo.b_bundle);
   236          //     bytes32 addressSHA3 = keccak256(bytes(tinfo.s_address));
   237  
   238          //     emit transactions_by_bundle(bundleSHA3, tinfo.transactionSHA3); // logs transactions per bundle, tighly packed bytes32 keccak hashes of transactions
   239          //     emit transactions_by_address(addressSHA3, tinfo.transactionSHA3); // logs transactions per address, tighly packed bytes32 keccak hashes of transactions
   240  
   241          //     // we also log in contract data, not just events, as that is faster for retrieval, and allows fast sync. Cost more storage though,
   242          //     // but you know... the things we accept for better performance...
   243          //     StoreTransactionsByAddress(addressSHA3, tinfo.transactionSHA3);
   244          //     StoreTransactionsByBundle(bundleSHA3, tinfo.transactionSHA3);
   245  
   246  
   247          // } // END LOOP THROUGH ALL TRANSACTIONS
   248  
   249          // // perform further overall checks:
   250  
   251          // // Check trunk/branch strucutre solid
   252          // // process each transaction hash we have seen in the bundle
   253          // for (uint32 transaction_idx = 0; transaction_idx < cnt_transactions; transaction_idx++){
   254          //     TransactionInfoStruct memory tcheck;
   255          //     tcheck.transactionSHA3 = tmpSha3TransactionHashes[transaction_idx] ;
   256          //     tcheck.transactionTrunkSHA3 = transaction_trunk[tcheck.transactionSHA3];
   257          //     tcheck.transactionBranchSHA3 = transaction_branch[tcheck.transactionSHA3];
   258          //     require(bytes(transactions[tcheck.transactionTrunkSHA3]).length != 0 ,"TRUNK TRANSACTION DOES NOT EXIST");
   259          //     require(bytes(transactions[tcheck.transactionBranchSHA3]).length != 0 ,"BRANCH TRANSACTION DOES NOT EXIST");
   260          // }
   261  
   262          // assert(totalBundleValue==0); // totalBundleValue must be 0 across the bundle;
   263  
   264          // // compute and check BUNDLE HASH: calculated bundle hash must match the actual bundle trytes stored in each transaction
   265  
   266          // string memory s_hash = CurlHashOP(string(all_essential_parts));
   267          // require (compareStrings(s_bundle,s_hash),"CALCULATED BUNDLE DIFFERS");
   268  
   269          // // if we are here, the bundle itself is valid. Now we have to check if there are enough balances available on the spending addresses
   270          // ValidateBalancesAndTransact(transactiondata);
   271  
   272          // // AND NOW, as the final step, we call ADKTransactionNotify on each receiving Contract
   273  
   274          // // Note: this is done last, to prevent reentry hacks, and we use CALL so we dont revert if the
   275          // // target is not a contract: The low-level functions call, delegatecall and staticcall return true as their first return value if the account called is non-existent, as part of the design of the EVM.
   276  
   277          // // note the GAS is limited here to  10000 gas to prevent spam
   278  
   279          // for (uint32 transaction_idx = 0; transaction_idx < cnt_transactions; transaction_idx++){
   280          //     TransactionInfoStruct memory tinfo2;
   281          //     tinfo2.offset = transaction_idx * 2673;
   282          //     tinfo2.transactionValue = TryteToIntValue(subbytes(b_trytes,tinfo2.offset+2268,tinfo2.offset+2279));
   283          //     if (tinfo2.transactionValue > 0){// only call for positive transactions
   284          //         tinfo2.s_address = substring(transactiondata,tinfo2.offset+2187,tinfo2.offset+2268);
   285          //         tinfo2.sigA = substring(transactiondata,tinfo2.offset+0,tinfo2.offset+2187);
   286  
   287          //         // the following calls the receiveing contract notification function (if it exists)
   288          //         address _addr = ADKTokenInterface(ADKTokenAddress).AZ9_TO_ADDR(tinfo2.s_address); // get the target address
   289          //         (bool success, bytes memory data) = _addr.call{value: 0, gas: 10000 }(
   290          //                 abi.encodeWithSignature("ADKMeshTransactionNotify(string,int256)", tinfo2.sigA, tinfo2.transactionValue)
   291          //         );
   292          //         require (success, "CALLED CONTRACT (ADKTransactionNotify) REVERTED.");
   293          //     }
   294          // }
   295  
   296          // mutex_PostTransactions = false; // end reentry check
   297          // return s_hash; // bundle hash
   298           require(false, "function not implemented"); //don't need ERC20 version any more
   299      }
   300      //
   301      // ValidateBalancesAndTransact - internal function that checks balances (sufficient balance) and performs the actual transfer
   302      //
   303      bool mutex2 = false;
   304      function ValidateBalancesAndTransact(string memory transactiondata) internal returns (bool){
   305  
   306          // require (!mutex2, "mutex check failed on ValidateBalancesAndTransact");
   307          // mutex2 = true;
   308  
   309          // //check transaction data once again, and then loop through all transactions.
   310          // // NOTE: at this point all signatures have already been validated.
   311  
   312          // bytes memory b_trytes = bytes(transactiondata);
   313          // require(b_trytes.length % 2673 == 0 && b_trytes.length > 0 ,"Invalid transaction(s) length");
   314          // uint16 cnt_transactions = uint16(b_trytes.length / 2673);
   315  
   316          // int total = 0;
   317  
   318          // // first calculate totals per address (in case the same address appears more than once in the bundle)
   319          // for (uint32 transaction_idx = 0; transaction_idx < cnt_transactions; transaction_idx++){ // loop through all transactions once
   320          //     uint32 offset = transaction_idx * 2673; // offset of current transaction
   321          //     string memory s_address = substring(transactiondata,uint32(offset+2187),uint32(offset+2268));
   322          //     int value = TryteToIntValue(subbytes(b_trytes,offset+2268,offset+2279));
   323          //     total += value;
   324          //     testBundleBalances[s_address] += value; // store it as temporary virtual balance (this entry was set to 0 initially in PostTransactions() )
   325          // }
   326          // assert(total==0); // we did that before already, but doesnt hurt to check again...
   327  
   328          // // now check if actual current TOTAL balance for each SPENDING address is sufficient
   329          // for (uint32 transaction_idx2 = 0; transaction_idx2 < cnt_transactions; transaction_idx2++){ // loop through all transactions once again, but know we know each address' final total aready
   330          //     uint32 offset = transaction_idx2 * 2673; // offset of current transaction
   331          //     string memory s_address = substring(transactiondata,uint32(offset+2187),uint32(offset+2268));
   332  
   333          //     int availableBalance = int(GetAZ9balanceOf(s_address)); // get this from current ADK balance
   334  
   335          //     // after the bundle values are applied on each address, the new balance must be >= 0
   336          //     require(availableBalance + testBundleBalances[s_address] >= 0, "INSUFFICIENT BALANCE");
   337  
   338          //     // PERFORM VALUE TRANSACTION. Note: ADKTokenContract.meshTransaction can only be called by this Transfer Contract
   339          //     if (testBundleBalances[s_address]!= 0){ // transaction is positive or negative, thus will update the address balance
   340          //         ADKTokenInterface(ADKTokenAddress).meshTransaction(s_address, testBundleBalances[s_address]);
   341          //     }
   342  
   343          //     testBundleBalances[s_address] = 0; //  reset to 0 now as we have done the TRANSACTION
   344          // }
   345          // mutex2 = false; // end reentry check
   346          // return true;
   347          require(false, "function not implemented"); //don't need ERC20 version any more
   348      }
   349  
   350       //
   351      //  Stores transaction hases by address, but depending on the number of tx we increment the SHA hash
   352      //
   353      function StoreTransactionsByAddress(bytes32 addressSHA3, bytes32 transactionSHA3) internal {
   354          uint32 cntAddrTx = transactionhash_by_address_count[addressSHA3];
   355          bytes32 addressSHA3_incl_cnt = bytes32(uint256(addressSHA3)+cntAddrTx);
   356          transactionhash_by_address[addressSHA3_incl_cnt] = transactionSHA3;
   357          cntAddrTx++;
   358          transactionhash_by_address_count[addressSHA3] = cntAddrTx;
   359      }
   360      //
   361      //  Stores transaction hases by address, but depending on the number of tx we increment the SHA hash
   362      //
   363      function StoreTransactionsByBundle(bytes32 bundleSHA3, bytes32 transactionSHA3) internal {
   364          uint32 cntBundleTx = transactionhash_by_bundle_count[bundleSHA3];
   365          bytes32 bundleSHA3_incl_cnt = bytes32(uint256(bundleSHA3)+cntBundleTx);
   366          transactionhash_by_bundle[bundleSHA3_incl_cnt] = transactionSHA3;
   367          cntBundleTx++;
   368          transactionhash_by_bundle_count[bundleSHA3] = cntBundleTx;
   369      }
   370      //
   371      // helper function view GetTxByAddress
   372      function GetTxByAddress(string memory addressString, uint256 numTx) public view returns (string memory) {
   373          bytes32 addr_b = keccak256(bytes(addressString));
   374          addr_b = bytes32(uint256(addr_b)+numTx);
   375          bytes32 txHash = transactionhash_by_address[addr_b];
   376          if (txHash == 0x000000000000000000000000000000000000000000000000) return "";
   377          return transaction_hashes[txHash];
   378      }
   379  
   380      //
   381      // helper function view GetTxByAddress
   382      function GetTxByBundle(string memory bundleString, uint256 numTx) public view returns (string memory) {
   383          bytes32 bundle_b = keccak256(bytes(bundleString));
   384          bundle_b = bytes32(uint256(bundle_b)+numTx);
   385          bytes32 txHash = transactionhash_by_bundle[bundle_b];
   386          if (txHash == 0x000000000000000000000000000000000000000000000000) return "";
   387          return transaction_hashes[txHash];
   388      }
   389  
   390      // Transaction Struct, mainly used to avoid stack issues
   391      struct TransactionInfoStruct {
   392            string s_address;
   393            string data; // transaction data
   394            int transactionValue;
   395            string sig2_address;
   396            int sig2_value;
   397            string sigA;
   398            string sigB;
   399            bytes b_lastIndex;
   400            bytes b_bundle;
   401            bytes b_currentIndex;
   402            int currentIndex;
   403            uint32 offset;
   404            bytes32 transactionSHA3; // KECCAK hash of transactionSHA3
   405            bytes trans_hash; // CURL hash of transaction
   406            bytes32 transactionTrunkSHA3;
   407            bytes32 transactionBranchSHA3;
   408      }
   409  
   410  
   411      // HELPER FUNCTIONS
   412  
   413      // Allows for upgrade of the ADK Token Contract while in Genesis Mode
   414      function ADM_SetADKTokenContract (address _newContract) public onlyGenesis {
   415          ADKTokenAddress = _newContract;
   416      }
   417  
   418      // Allows for upgrade of the ADK Genesis Address
   419      // and will be used to force-lock the contract by setting to 0x00000000[..] so no further updates are possible
   420      function ADM_SetGenesisAddress (address _genesisAddress) public onlyGenesis {
   421          adkgo_genesis_address = _genesisAddress;
   422      }
   423  
   424      // Allows Tip adjustment while in Genesis Mode
   425      function ADM_SetTip (bytes32 _newTip) public onlyGenesis {
   426            meshTip = _newTip;
   427      }
   428  
   429      // Allows Difficulty adjustment while in Genesis Mode
   430      function ADM_SetDifficulty (uint256 _ClientProofOfWorkRequirement) public onlyGenesis {
   431            ClientProofOfWorkRequirement = _ClientProofOfWorkRequirement;
   432      }
   433  
   434      // Allows data migration from old ADK node while in Genesis Mode
   435      function ADM_LoadTransactionsUnchecked (string memory _transaction) public mod_requireAZ9(_transaction) onlyGenesis {
   436          bytes memory b_trytes = bytes(_transaction);
   437          require(bytes(_transaction).length == 2673,"INVALID TRANSACTION LENGTH");
   438          TransactionInfoStruct memory tinfo;
   439          tinfo.data = _transaction;
   440  		tinfo.trans_hash = bytes(CurlHashOP(tinfo.data));  // Call the Hash Operation in order to get the transaction hash
   441          tinfo.transactionSHA3 = keccak256(tinfo.trans_hash);
   442          transactions[tinfo.transactionSHA3] = string(tinfo.data); // store transaction
   443          transaction_hashes[tinfo.transactionSHA3] = string(tinfo.trans_hash); // store transaction hash
   444  
   445          tinfo.transactionTrunkSHA3 = keccak256(subbytes(b_trytes,uint32(2430),uint32(2430+81)));
   446          tinfo.transactionBranchSHA3 = keccak256(subbytes(b_trytes,uint32(2511),uint32(2511+81)));
   447  
   448          // store trunk and branch
   449          transaction_trunk[tinfo.transactionSHA3] = tinfo.transactionTrunkSHA3;
   450          transaction_branch[tinfo.transactionSHA3] = tinfo.transactionBranchSHA3;
   451  
   452          tinfo.s_address = substring(tinfo.data,2187,2268);
   453          tinfo.b_bundle = subbytes(b_trytes,2349,2349+81);
   454  
   455          //log for faster retrieval later
   456          bytes32 addrSHA3 = keccak256(bytes(tinfo.s_address));
   457          bytes32 bundSHA3 = keccak256(bytes(tinfo.b_bundle));
   458  
   459          emit transactions_by_bundle(bundSHA3, tinfo.transactionSHA3); // logs transactions per bundle, tighly packed bytes32 keccak hashes of transactions
   460          emit transactions_by_address(addrSHA3, tinfo.transactionSHA3); // logs transactions per address, tighly packed bytes32 keccak hashes of transactions
   461          StoreTransactionsByBundle(bundSHA3, tinfo.transactionSHA3);
   462          StoreTransactionsByAddress(addrSHA3, tinfo.transactionSHA3);
   463      }
   464  
   465      // Allows for initial load of Balances while in Genesis Mode
   466      function ADM_LoadADKBalances (string memory _address, int _value) public onlyGenesis {
   467          ADKTokenInterface(ADKTokenAddress).meshTransaction(_address, _value);
   468      }
   469      // Allows for initial load of Balances while in Genesis Mode/ bulk mode for speedup
   470      function ADM_LoadADKBalancesBulk (string memory _addresses,
   471                                          int _value1,
   472                                          int _value2,
   473                                          int _value3,
   474                                          int _value4,
   475                                          int _value5,
   476                                          int _value6,
   477                                          int _value7,
   478                                          int _value8,
   479                                          int _value9,
   480                                          int _value10
   481                                          )  public onlyGenesis {
   482          uint32 pos = 0;
   483          require (bytes(_addresses).length == 81 * 10 , "String must contain 10 addresses without checksum for bulk processing");
   484          ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value1); pos+= 81;
   485          ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value2); pos+= 81;
   486          ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value3); pos+= 81;
   487          ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value4); pos+= 81;
   488          ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value5); pos+= 81;
   489          ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value6); pos+= 81;
   490          ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value7); pos+= 81;
   491          ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value8); pos+= 81;
   492          ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value9); pos+= 81;
   493          ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value10);
   494      }
   495  
   496      // Events (Logging)
   497      event EventLogString(string indexed info, string strdata);
   498      event EventLogInt(string indexed info, int intdata);
   499      event EventLogUInt(string indexed info, uint uintdata);
   500  
   501      //
   502      // Additional helper functions / tools
   503  
   504      // Convert a single tryte to 3 trits
   505      function TryteToTrits (uint16 test) public pure returns (int16[3] memory){
   506                 // TO DO  use modulo instead.
   507                 if (test == 57)return [int16(0),int16(0),int16(0)]; // 9 // special case
   508                 require(test >= 65 && test <= 90,"INVALID TRYTE");
   509                 uint16 base = test + 3;  // 68 is the base, that perfectly matches the modulo so that e.g. 65 becomes 1/0/0
   510                 return [
   511                          int16(base % 3)-1,
   512                          int16((base/3) % 3)-1,
   513                          int16((base/9) % 3)-1
   514                     ];
   515      }
   516  
   517      // Convert value-trytes to actual values
   518      function TryteToIntValue(bytes memory data) public pure  returns (int) {
   519          int ret = 0;
   520  
   521          for (uint i = data.length; i > 0; i--) { // have to use >0 and then -1 because otherwise uint becomes negative and transaction reverts
   522              int16[3] memory trits = TryteToTrits(uint8(data[i-1]));
   523              ret = ret * 3 + trits[2];
   524              ret = ret * 3 + trits[1];
   525              ret = ret * 3 + trits[0];
   526          }
   527          return ret;
   528      }
   529  
   530      // Checks if two strings are identical
   531      function compareStrings(string memory a, string memory b) internal pure returns (bool) {
   532          return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))));
   533      }
   534  
   535      // CurlHashOP - calculates a CURL hash for a given Tryte string
   536      function CurlHashOP(string memory str) public pure returns (string memory){
   537  
   538          bytes memory pdata = bytes(string(abi.encodePacked("{CURL}", "HASH", bytes1(0x00), bytes1(0x00), str)));
   539          bytes32 r1 = keccak256(pdata);
   540          pdata[10] = 0x20; // next 32 chars
   541          bytes32 r2 = keccak256(pdata);
   542          pdata[10] = 0x40; // next 32 chars
   543          bytes32 r3 = keccak256(pdata);
   544  
   545          bytes memory ret = new bytes(81);
   546  
   547          for (uint i = 0; i< 32; i++){ // 0-64
   548              ret[i] = r1[i];
   549              ret[32+i] = r2[i];
   550          }
   551          for (uint i = 0; i < 17; i++){ // 64-81
   552              ret[64+i] = r3[i];
   553          }
   554  
   555          return string(ret);
   556      }
   557  
   558      // Calls the ADK (gadk) Signature Validation Routine via the overloaded keccak function
   559  
   560      function CurlValidateSignature(string memory addr, string memory signature, string memory bundle) internal pure returns (bool){
   561  
   562          bytes memory pdata = bytes(string(abi.encodePacked("{CURL}", "VALSIG", addr,signature,bundle)));
   563          bytes32 result = keccak256(pdata);
   564  
   565          return uint(result)==0;  // must be 0, only then the signature is valid
   566      }
   567  
   568      // substring helper function
   569      function substring(string memory str, uint32 startIndex, uint32 endIndex) internal pure returns (string memory ) {
   570          bytes memory strBytes = bytes(str);
   571          bytes memory result = new bytes(endIndex-startIndex);
   572          for(uint32 i = startIndex; i < endIndex; i++) {
   573              result[i-startIndex] = strBytes[i];
   574          }
   575          return string(result);
   576      }
   577  
   578      // subbytes helper function
   579      function subbytes(bytes memory strBytes, uint startIndex, uint endIndex) internal pure returns (bytes memory ) {
   580          bytes memory result = new bytes(endIndex-startIndex);
   581          for(uint i = startIndex; i < endIndex; i++) {
   582              result[i-startIndex] = strBytes[i];
   583          }
   584          return result;
   585      }
   586  
   587      // concat (strings) helper function
   588      function concat(string memory a, string memory b) internal pure returns (string memory) {
   589          return string(abi.encodePacked(a, b,"","",""));
   590      }
   591  
   592      //
   593      // Modifiers    /////////////////////////////////////////////////
   594      //
   595  
   596      modifier mod_requireAZ9 (string memory _adk_string) {
   597          bytes memory adkBytes = bytes (_adk_string);
   598          require(adkBytes.length >= 1 );
   599  
   600          bool valid = true;
   601          for (uint i = 0; i < adkBytes.length; i++) {
   602              if (
   603                  ! (
   604                      uint8(adkBytes[i]) == 57 //9
   605                       || (uint8(adkBytes[i]) >= 65 && uint8(adkBytes[i]) <= 90) //A-Z
   606                    )
   607                 ) valid = false;
   608          }
   609          require (valid, "INVALID TRYTES");
   610          _;
   611      }
   612   
   613      // MODIFIERS
   614  
   615      modifier onlyGenesis {
   616          require(msg.sender == adkgo_genesis_address, "NOT AUTHORIZED");
   617          _;
   618      }
   619  
   620  }