hello and ack exchange
This commit is contained in:
@@ -6,13 +6,15 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
PACKET_TYPE_NONE = 0,
|
PACKET_TYPE_NONE = 0,
|
||||||
PACKET_TYPE_HELLO = 1, // Hello, let's connect! Here's who I am, and what I have!
|
PACKET_TYPE_HELLO = 1, // Hello, let's connect! Here's who I am, and what I have!
|
||||||
PACKET_TYPE_FETCH_BLOCK = 2, // I want a Block
|
PACKET_TYPE_ACK_HELLO = 2, // I received your hello, here's who I am and what I have (response to hello)
|
||||||
PACKET_TYPE_BLOCK_DATA = 3, // Here's a Block (response to fetch) - I don't care what you do with it, but you wanted it, so here it is!
|
PACKET_TYPE_FETCH_BLOCK = 3, // I want a Block
|
||||||
PACKET_TYPE_BROADCAST_BLOCK = 4, // Here's a new Block I want to share with the network (unsolicited - e.g. just mined it)
|
PACKET_TYPE_BLOCK_DATA = 4, // Here's a Block (response to fetch) - I don't care what you do with it, but you wanted it, so here it is!
|
||||||
PACKET_TYPE_ACK_BLOCK = 5, // I have received your block, here's what I did with it (response to broadcast)
|
PACKET_TYPE_BROADCAST_BLOCK = 5, // Here's a new Block I want to share with the network (unsolicited - e.g. just mined it)
|
||||||
PACKET_TYPE_BROADCAST_TX = 6, // Here's a new transaction I want to share with the network
|
PACKET_TYPE_ACK_BLOCK = 6, // I have received your block, here's what I did with it (response to broadcast)
|
||||||
PACKET_TYPE_ACK_TX = 7, // I have received your transaction, here's what I did with it (response to broadcast)
|
PACKET_TYPE_BROADCAST_TX = 7, // Here's a new transaction I want to share with the network
|
||||||
PACKET_TYPE_MAX = 9
|
PACKET_TYPE_ACK_TX = 8, // I have received your transaction, here's what I did with it (response to broadcast)
|
||||||
|
PACKET_TYPE_ERROR = 9, // Something went wrong with the packet you sent me, here's an error message (can be response to any packet)
|
||||||
|
PACKET_TYPE_MAX = 10
|
||||||
} packet_type_t;
|
} packet_type_t;
|
||||||
|
|
||||||
static inline int PacketType_IsValid(uint8_t packetType) {
|
static inline int PacketType_IsValid(uint8_t packetType) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ KHASH_INIT(tx_mempool_map_m, key32_t, signed_transaction_t, 1, hash_key32, eq_ke
|
|||||||
extern khash_t(tx_mempool_map_m)* txMempool;
|
extern khash_t(tx_mempool_map_m)* txMempool;
|
||||||
|
|
||||||
void TxMempool_Init();
|
void TxMempool_Init();
|
||||||
|
// Assumed that the transation was confirmed to be valid
|
||||||
int TxMempool_Insert(signed_transaction_t tx);
|
int TxMempool_Insert(signed_transaction_t tx);
|
||||||
bool TxMempool_Lookup(uint8_t* txHash, signed_transaction_t* out);
|
bool TxMempool_Lookup(uint8_t* txHash, signed_transaction_t* out);
|
||||||
void TxMempool_Print();
|
void TxMempool_Print();
|
||||||
|
|||||||
132
include/utils.h
132
include/utils.h
@@ -5,6 +5,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <uint256.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t bytes[32];
|
uint8_t bytes[32];
|
||||||
@@ -30,4 +31,135 @@ static inline void AddressToHexString(const uint8_t address[32], char out[65]) {
|
|||||||
to_hex(address, out);
|
to_hex(address, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool ParseHexAddress32(const char* in, uint8_t outAddress[32]) {
|
||||||
|
if (!in || !outAddress) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* p = in;
|
||||||
|
if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(p) != 64) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 32; ++i) {
|
||||||
|
char hi = p[i * 2];
|
||||||
|
char lo = p[i * 2 + 1];
|
||||||
|
int hiVal = (hi >= '0' && hi <= '9') ? (hi - '0') :
|
||||||
|
(hi >= 'a' && hi <= 'f') ? (10 + hi - 'a') :
|
||||||
|
(hi >= 'A' && hi <= 'F') ? (10 + hi - 'A') : -1;
|
||||||
|
int loVal = (lo >= '0' && lo <= '9') ? (lo - '0') :
|
||||||
|
(lo >= 'a' && lo <= 'f') ? (10 + lo - 'a') :
|
||||||
|
(lo >= 'A' && lo <= 'F') ? (10 + lo - 'A') : -1;
|
||||||
|
|
||||||
|
if (hiVal < 0 || loVal < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outAddress[i] = (uint8_t)((hiVal << 4) | loVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool IsValidIPv4(const char* ip) {
|
||||||
|
if (!ip || *ip == '\0') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int octetCount = 0;
|
||||||
|
const char* p = ip;
|
||||||
|
|
||||||
|
while (*p != '\0') {
|
||||||
|
if (octetCount >= 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p < '0' || *p > '9') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int value = 0;
|
||||||
|
int digits = 0;
|
||||||
|
while (*p >= '0' && *p <= '9') {
|
||||||
|
value = (value * 10u) + (unsigned int)(*p - '0');
|
||||||
|
if (value > 255u) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
++digits;
|
||||||
|
if (digits > 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (digits == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
++octetCount;
|
||||||
|
if (octetCount < 4) {
|
||||||
|
if (*p != '.') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
if (*p == '\0') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return octetCount == 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void Uint256ToDecimal(const uint256_t* value, char* out, size_t outSize) {
|
||||||
|
if (!value || !out || outSize == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t tmp[4] = {
|
||||||
|
value->limbs[0],
|
||||||
|
value->limbs[1],
|
||||||
|
value->limbs[2],
|
||||||
|
value->limbs[3]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tmp[0] == 0 && tmp[1] == 0 && tmp[2] == 0 && tmp[3] == 0) {
|
||||||
|
if (outSize >= 2) {
|
||||||
|
out[0] = '0';
|
||||||
|
out[1] = '\0';
|
||||||
|
} else {
|
||||||
|
out[0] = '\0';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char digits[80];
|
||||||
|
size_t digitCount = 0;
|
||||||
|
|
||||||
|
while (tmp[0] != 0 || tmp[1] != 0 || tmp[2] != 0 || tmp[3] != 0) {
|
||||||
|
uint64_t remainder = 0;
|
||||||
|
for (int i = 3; i >= 0; --i) {
|
||||||
|
__uint128_t cur = ((__uint128_t)remainder << 64) | tmp[i];
|
||||||
|
tmp[i] = (uint64_t)(cur / 10u);
|
||||||
|
remainder = (uint64_t)(cur % 10u);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (digitCount < sizeof(digits) - 1) {
|
||||||
|
digits[digitCount++] = (char)('0' + remainder);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t writeLen = (digitCount < (outSize - 1)) ? digitCount : (outSize - 1);
|
||||||
|
for (size_t i = 0; i < writeLen; ++i) {
|
||||||
|
out[i] = digits[digitCount - 1 - i];
|
||||||
|
}
|
||||||
|
out[writeLen] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
107
src/main.c
107
src/main.c
@@ -84,53 +84,6 @@ static bool GenerateTestMinerIdentity(uint8_t privateKey[32], uint8_t compressed
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Uint256ToDecimal(const uint256_t* value, char* out, size_t outSize) {
|
|
||||||
if (!value || !out || outSize == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t tmp[4] = {
|
|
||||||
value->limbs[0],
|
|
||||||
value->limbs[1],
|
|
||||||
value->limbs[2],
|
|
||||||
value->limbs[3]
|
|
||||||
};
|
|
||||||
|
|
||||||
if (tmp[0] == 0 && tmp[1] == 0 && tmp[2] == 0 && tmp[3] == 0) {
|
|
||||||
if (outSize >= 2) {
|
|
||||||
out[0] = '0';
|
|
||||||
out[1] = '\0';
|
|
||||||
} else {
|
|
||||||
out[0] = '\0';
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char digits[80];
|
|
||||||
size_t digitCount = 0;
|
|
||||||
|
|
||||||
while (tmp[0] != 0 || tmp[1] != 0 || tmp[2] != 0 || tmp[3] != 0) {
|
|
||||||
uint64_t remainder = 0;
|
|
||||||
for (int i = 3; i >= 0; --i) {
|
|
||||||
__uint128_t cur = ((__uint128_t)remainder << 64) | tmp[i];
|
|
||||||
tmp[i] = (uint64_t)(cur / 10u);
|
|
||||||
remainder = (uint64_t)(cur % 10u);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (digitCount < sizeof(digits) - 1) {
|
|
||||||
digits[digitCount++] = (char)('0' + remainder);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t writeLen = (digitCount < (outSize - 1)) ? digitCount : (outSize - 1);
|
|
||||||
for (size_t i = 0; i < writeLen; ++i) {
|
|
||||||
out[i] = digits[digitCount - 1 - i];
|
|
||||||
}
|
|
||||||
out[writeLen] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool MineBlock(block_t* block) {
|
static bool MineBlock(block_t* block) {
|
||||||
if (!block) {
|
if (!block) {
|
||||||
return false;
|
return false;
|
||||||
@@ -148,40 +101,6 @@ static bool MineBlock(block_t* block) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseHexAddress32(const char* in, uint8_t outAddress[32]) {
|
|
||||||
if (!in || !outAddress) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* p = in;
|
|
||||||
if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
|
|
||||||
p += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(p) != 64) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < 32; ++i) {
|
|
||||||
char hi = p[i * 2];
|
|
||||||
char lo = p[i * 2 + 1];
|
|
||||||
int hiVal = (hi >= '0' && hi <= '9') ? (hi - '0') :
|
|
||||||
(hi >= 'a' && hi <= 'f') ? (10 + hi - 'a') :
|
|
||||||
(hi >= 'A' && hi <= 'F') ? (10 + hi - 'A') : -1;
|
|
||||||
int loVal = (lo >= '0' && lo <= '9') ? (lo - '0') :
|
|
||||||
(lo >= 'a' && lo <= 'f') ? (10 + lo - 'a') :
|
|
||||||
(lo >= 'A' && lo <= 'F') ? (10 + lo - 'A') : -1;
|
|
||||||
|
|
||||||
if (hiVal < 0 || loVal < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
outAddress[i] = (uint8_t)((hiVal << 4) | loVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool FlushChainAndSheet(blockchain_t* chain,
|
static bool FlushChainAndSheet(blockchain_t* chain,
|
||||||
const char* chainDataDir,
|
const char* chainDataDir,
|
||||||
uint256_t currentSupply,
|
uint256_t currentSupply,
|
||||||
@@ -507,7 +426,7 @@ int main(int argc, char* argv[]) {
|
|||||||
char supplyStr[80];
|
char supplyStr[80];
|
||||||
Uint256ToDecimal(¤tSupply, supplyStr, sizeof(supplyStr));
|
Uint256ToDecimal(¤tSupply, supplyStr, sizeof(supplyStr));
|
||||||
printf("Current chain has %zu blocks, total supply %s\n", Chain_Size(chain), supplyStr);
|
printf("Current chain has %zu blocks, total supply %s\n", Chain_Size(chain), supplyStr);
|
||||||
printf("Commands: mine <x>, send <address> <amount>, balance [address], flushchain, fullverify, wipechain, genaddr, exit\n");
|
printf("Commands: mine <x>, send <address> <amount>, balance [address], connect <ipv4>, flushchain, fullverify, wipechain, genaddr, exit\n");
|
||||||
|
|
||||||
char line[1024];
|
char line[1024];
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -682,6 +601,28 @@ int main(int argc, char* argv[]) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcmp(cmd, "connect") == 0) {
|
||||||
|
char* ipStr = strtok(NULL, " \t");
|
||||||
|
char* extra = strtok(NULL, " \t");
|
||||||
|
if (!ipStr || extra) {
|
||||||
|
printf("usage: connect <ipv4>\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValidIPv4(ipStr)) {
|
||||||
|
printf("invalid IPv4 address\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Node_ConnectPeer(node, ipStr, LISTEN_PORT) != 0) {
|
||||||
|
printf("failed to connect to %s:%u\n", ipStr, (unsigned int)LISTEN_PORT);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("connect requested to %s:%u\n", ipStr, (unsigned int)LISTEN_PORT);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(cmd, "flushchain") == 0) {
|
if (strcmp(cmd, "flushchain") == 0) {
|
||||||
if (FlushChainAndSheet(chain, chainDataDir, currentSupply, currentReward)) {
|
if (FlushChainAndSheet(chain, chainDataDir, currentSupply, currentReward)) {
|
||||||
printf("chain flushed\n");
|
printf("chain flushed\n");
|
||||||
@@ -758,7 +699,7 @@ int main(int argc, char* argv[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Unknown command. Available: mine, send, balance, flushchain, fullverify, wipechain, genaddr, exit\n");
|
printf("Unknown command. Available: mine, send, balance, connect, flushchain, fullverify, wipechain, genaddr, exit\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)FlushChainAndSheet(chain, chainDataDir, currentSupply, currentReward);
|
(void)FlushChainAndSheet(chain, chainDataDir, currentSupply, currentReward);
|
||||||
|
|||||||
@@ -218,15 +218,47 @@ void Node_Server_OnData(tcp_connection_t* client) {
|
|||||||
printf("Received HELLO from node %u: protoVersion=%u, blockHeight=%" PRIu64 "\n",
|
printf("Received HELLO from node %u: protoVersion=%u, blockHeight=%" PRIu64 "\n",
|
||||||
client ? client->connectionId : 0U, protoVersion, blockHeight);
|
client ? client->connectionId : 0U, protoVersion, blockHeight);
|
||||||
|
|
||||||
|
// Craft and send ACK_HELLO
|
||||||
|
uint8_t ackBuf[100];
|
||||||
|
uint8_t* ackData = ackBuf;
|
||||||
|
size_t ackOffset = 0;
|
||||||
|
memcpy(ackData + ackOffset, &protoVersion, sizeof(protoVersion));
|
||||||
|
ackOffset += sizeof(protoVersion);
|
||||||
|
memcpy(ackData + ackOffset, ¤tBlockHeight, sizeof(currentBlockHeight));
|
||||||
|
ackOffset += sizeof(currentBlockHeight);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PACKET_TYPE_ACK_HELLO: {
|
||||||
|
// This is illegal
|
||||||
|
printf("Received unexpected ACK_HELLO packet from node %u\n", client ? client->connectionId : 0U);
|
||||||
|
|
||||||
|
// Send the error and kill the connection
|
||||||
|
const char* msg = "You can't ACK_HELLO me! I'm a server!";
|
||||||
|
Node_SendPacket(Node_FromConnection(client), client, PACKET_TYPE_ERROR, msg, strlen(msg));
|
||||||
|
TcpConnection_RequestClose(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
case PACKET_TYPE_FETCH_BLOCK:
|
case PACKET_TYPE_FETCH_BLOCK:
|
||||||
case PACKET_TYPE_BLOCK_DATA:
|
case PACKET_TYPE_BLOCK_DATA:
|
||||||
case PACKET_TYPE_BROADCAST_BLOCK:
|
case PACKET_TYPE_BROADCAST_BLOCK:
|
||||||
case PACKET_TYPE_ACK_BLOCK:
|
case PACKET_TYPE_ACK_BLOCK:
|
||||||
case PACKET_TYPE_BROADCAST_TX:
|
case PACKET_TYPE_BROADCAST_TX:
|
||||||
case PACKET_TYPE_ACK_TX:
|
case PACKET_TYPE_ACK_TX:
|
||||||
|
case PACKET_TYPE_ERROR: {
|
||||||
|
// Decode the message inside as text
|
||||||
|
char* text = (char*)malloc(payloadLen + 1);
|
||||||
|
if (!text) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(text, payload, payloadLen);
|
||||||
|
text[payloadLen] = '\0';
|
||||||
|
printf("Received packet type %u from node %u with message: %s\n",
|
||||||
|
(unsigned int)packetType, client ? client->connectionId : 0U, text);
|
||||||
|
free(text);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -273,14 +305,50 @@ void Node_Client_OnData(tcp_connection_t* client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (packetType) {
|
switch (packetType) {
|
||||||
case PACKET_TYPE_HELLO:
|
case PACKET_TYPE_HELLO: {
|
||||||
|
// This is illegal
|
||||||
|
printf("Received unexpected HELLO packet from node %u\n", client ? client->connectionId : 0U);
|
||||||
|
|
||||||
|
// Send the error and kill the connection
|
||||||
|
const char* msg = "You can't HELLO me! I'm a client!";
|
||||||
|
Node_SendPacket(Node_FromConnection(client), client, PACKET_TYPE_ERROR, msg, strlen(msg));
|
||||||
|
TcpConnection_RequestClose(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case PACKET_TYPE_ACK_HELLO: {
|
||||||
|
// Decode ACK_HELLO
|
||||||
|
if (payloadLen < sizeof(uint32_t) + sizeof(uint64_t)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t protoVersion;
|
||||||
|
uint64_t blockHeight;
|
||||||
|
memcpy(&protoVersion, payload, sizeof(protoVersion));
|
||||||
|
memcpy(&blockHeight, payload + sizeof(protoVersion), sizeof(blockHeight));
|
||||||
|
|
||||||
|
printf("Received ACK_HELLO from node %u with protoVersion %u and blockHeight %lu\n", client ? client->connectionId : 0U, protoVersion, (unsigned long)blockHeight);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case PACKET_TYPE_FETCH_BLOCK:
|
case PACKET_TYPE_FETCH_BLOCK:
|
||||||
case PACKET_TYPE_BLOCK_DATA:
|
case PACKET_TYPE_BLOCK_DATA:
|
||||||
case PACKET_TYPE_BROADCAST_BLOCK:
|
case PACKET_TYPE_BROADCAST_BLOCK:
|
||||||
case PACKET_TYPE_ACK_BLOCK:
|
case PACKET_TYPE_ACK_BLOCK:
|
||||||
case PACKET_TYPE_BROADCAST_TX:
|
case PACKET_TYPE_BROADCAST_TX:
|
||||||
case PACKET_TYPE_ACK_TX:
|
case PACKET_TYPE_ACK_TX:
|
||||||
|
case PACKET_TYPE_ERROR: {
|
||||||
|
// Decode the message inside as text
|
||||||
|
char* text = (char*)malloc(payloadLen + 1);
|
||||||
|
if (!text) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(text, payload, payloadLen);
|
||||||
|
text[payloadLen] = '\0';
|
||||||
|
printf("Received packet type %u from node %u with message: %s\n",
|
||||||
|
(unsigned int)packetType, client ? client->connectionId : 0U, text);
|
||||||
|
free(text);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ int TxMempool_Insert(signed_transaction_t tx) {
|
|||||||
if (!txMempool) { return -1; }
|
if (!txMempool) { return -1; }
|
||||||
|
|
||||||
uint8_t txHash[32];
|
uint8_t txHash[32];
|
||||||
Transaction_CalculateHash(&tx.transaction, txHash);
|
Transaction_CalculateHash(&tx, txHash);
|
||||||
|
|
||||||
key32_t key;
|
key32_t key;
|
||||||
memcpy(key.bytes, txHash, 32);
|
memcpy(key.bytes, txHash, 32);
|
||||||
|
|||||||
Reference in New Issue
Block a user