Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6cf1b13500 | |||
| 4a8d4ab8d9 | |||
| 65a9574e52 | |||
| 6eacb677a4 | |||
| d081c8ea74 | |||
| 0342e7ffb5 | |||
| c029e5c39d | |||
| a917a9493c | |||
| 02405bb8ff | |||
| d8bb85a1d8 | |||
| fd6b2360aa | |||
| 3e655961e9 | |||
| 077837054b | |||
| 45674ef554 | |||
| eabf856dbd | |||
| 32ea0f2cf6 | |||
| 47f40c0be3 | |||
| 6a66615f37 |
+12
-12
@@ -21,7 +21,7 @@ jobs:
|
||||
sudo apt install -y git build-essential cmake libuv1-dev libzmq3-dev libsodium-dev libpgm-dev libnorm-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev ${{ matrix.config.c }} ${{ matrix.config.cpp }}
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
run: cd tests/build && ./p2pool_tests
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-${{ matrix.config.os }}
|
||||
path: build/p2pool
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100 --slave /usr/bin/g++ g++ /usr/bin/g++-12 --slave /usr/bin/gcov gcov /usr/bin/gcov-12
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
run: cd tests/build && ./p2pool_tests
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-ubuntu-static-libs
|
||||
path: build/p2pool
|
||||
@@ -131,7 +131,7 @@ jobs:
|
||||
sudo apt install -y git build-essential cmake autoconf gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -166,7 +166,7 @@ jobs:
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-${{ matrix.config.os }}-aarch64
|
||||
path: build/p2pool
|
||||
@@ -181,7 +181,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -235,7 +235,7 @@ jobs:
|
||||
./p2pool_tests.exe
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-msys2.exe
|
||||
path: build/p2pool.exe
|
||||
@@ -253,7 +253,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -281,7 +281,7 @@ jobs:
|
||||
./p2pool_tests.exe
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-msbuild-${{ matrix.config.os }}-randomx-${{ matrix.config.rx }}.exe
|
||||
path: build/Release/p2pool.exe
|
||||
@@ -296,7 +296,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -347,7 +347,7 @@ jobs:
|
||||
./p2pool_tests
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-${{ matrix.os }}
|
||||
path: build/p2pool
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
sudo apt update && sudo apt install git build-essential cmake libuv1-dev libzmq3-dev libsodium-dev libpgm-dev libnorm-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
# run: cmake --build ${{ env.build }}
|
||||
|
||||
- name: Initialize MSVC Code Analysis
|
||||
uses: microsoft/msvc-code-analysis-action@1e7491d1428ffa2e8aa70916d0d0309c7ca32baf
|
||||
uses: microsoft/msvc-code-analysis-action@24c285ab36952c9e9182f4b78dfafbac38a7e5ee
|
||||
# Provide a unique ID to access the sarif output path
|
||||
id: run-analysis
|
||||
with:
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
|
||||
# Upload SARIF file as an Artifact to download and view
|
||||
- name: Upload SARIF as an Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sarif-file
|
||||
path: ${{ steps.run-analysis.outputs.sarif }}
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
sudo apt install -y git build-essential cmake libuv1-dev libzmq3-dev libsodium-dev libpgm-dev libnorm-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev gcc-12 g++-12
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
./p2pool --host p2pmd.xmrvsbeast.com --zmq-port 18084 --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --no-cache --loglevel 6
|
||||
|
||||
- name: Archive p2pool.log
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_ubuntu.log
|
||||
path: build/p2pool.log
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
./p2pool --host p2pmd.xmrvsbeast.com --zmq-port 18084 --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --no-cache --loglevel 6
|
||||
|
||||
- name: Archive p2pool.log
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_macos.log
|
||||
path: build/p2pool.log
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
./p2pool.exe --host p2pmd.xmrvsbeast.com --zmq-port 18084 --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --no-cache --loglevel 6
|
||||
|
||||
- name: Archive p2pool.log
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_windows.log
|
||||
path: build/Debug/p2pool.log
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ if (NOT STATIC_BINARY AND NOT STATIC_LIBS)
|
||||
endif()
|
||||
|
||||
if (CURL_INCLUDE_DIRS)
|
||||
include_directories(CURL_INCLUDE_DIRS)
|
||||
include_directories(${CURL_INCLUDE_DIRS})
|
||||
else()
|
||||
include_directories(external/src/curl/include)
|
||||
endif()
|
||||
|
||||
@@ -76,13 +76,13 @@ Monero network upgrade happened on August 13th, 2022 (block 2,688,888). In order
|
||||
|
||||
### General Considerations
|
||||
|
||||
- In order to mine on P2Pool, a synced Monero node using monerod v0.18.0.0 or newer is required. If you do not currently have one configured, you can find instructions to do so [here](https://sethforprivacy.com/guides/run-a-monero-node-advanced/).
|
||||
- It is highly recommended that you create a separate restricted user account for mining. While P2Pool has been battle-tested for a long time now, any software may have unknown bugs/vulnerabilities.
|
||||
- In order to mine on P2Pool, a synced Monero node using monerod v0.18.0.0 or newer is required. If you don't currently have one, you can download the official Monero binaries, start `monerod` on your PC and wait until it's fully synced. Advanced Monero node setup instructions are [here](https://sethforprivacy.com/guides/run-a-monero-node-advanced/).
|
||||
- It is highly recommended that you create a separate restricted user account (in your OS) for mining. While P2Pool has been battle-tested for a long time now, any software may have unknown bugs/vulnerabilities.
|
||||
- You have to use a primary wallet address for mining. Subaddresses and integrated addresses are not supported, just like with monerod solo mining.
|
||||
- Starting from P2Pool v1.7, you can add the `--mini` parameter to your P2Pool command to connect to the **p2pool-mini** sidechain. Note that it will also change the default p2p port from 37889 to 37888.
|
||||
- You can add the `--mini` parameter to your P2Pool command to connect to the **p2pool-mini** sidechain. Note that it will also change the default p2p port from 37889 to 37888.
|
||||
- Check that ports 18080 (Monero p2p port) and 37889/37888 (P2Pool/P2Pool mini p2p port) are open in your firewall to ensure better connectivity. If you're mining from a computer behind NAT (like a router) you could consider forwarding the ports to your local machine.
|
||||
- You can connect multiple miners to the same P2Pool node. The more the better!
|
||||
- The below steps assume that you run everything on the same machine. If it's not the case, change `127.0.0.1` to appropriate IP addresses for your setup.
|
||||
- The steps below assume that you run everything on the same machine. If it's not the case, change `127.0.0.1` to appropriate IP addresses for your setup.
|
||||
- It is highly recommended to create a new mainnet wallet for P2Pool mining because **wallet addresses are public on P2Pool**.
|
||||
|
||||
**Wallet software compatible with P2Pool payouts**
|
||||
@@ -93,6 +93,10 @@ Monero network upgrade happened on August 13th, 2022 (block 2,688,888). In order
|
||||
- [Feather Wallet v2.1.0 and newer](https://featherwallet.org/)
|
||||
- [MyMonero](https://mymonero.com/)
|
||||
|
||||
### GUI for P2Pool
|
||||
|
||||
- [Gupax](https://github.com/hinto-janaiyo/gupax) project (currently in development) aims to provide an easy to use GUI to configure and run monerod/p2pool/xmrig
|
||||
|
||||
### GNU/Linux
|
||||
|
||||
1. Download the latest P2Pool binaries [here](https://github.com/SChernykh/p2pool/releases/latest).
|
||||
@@ -156,21 +160,23 @@ nocreate
|
||||
5. Prepare huge pages to work properly (each instance of monerod/P2Pool/XMRig needs them):
|
||||
- On Windows 10 or above, run XMRig at least once as Administrator (right-click Run As Administrator)
|
||||
- On earlier versions of Windows, you'll need to run XMRig as Administrator at least once per login.
|
||||
6. Open a command prompt and navigate to the folder where you extracted P2Pool.
|
||||
6. Create "Monero" folder inside extracted P2Pool folder and copy Monero binaries there.
|
||||
7. Open a command prompt and navigate to the folder where you extracted P2Pool.
|
||||
|
||||
**Note:** *When running the below commands, Windows Firewall may prompt to allow connections, click "Allow" if prompted.*
|
||||
|
||||
7. Start `monerod` with the following command/options:
|
||||
8. Start `monerod` with the following command/options:
|
||||
```
|
||||
.\Monero\monerod.exe --zmq-pub tcp://127.0.0.1:18083 --disable-dns-checkpoints --enable-dns-blocklist
|
||||
```
|
||||
**Note:** The `--zmq-pub` option is required for P2Pool to work properly.
|
||||
8. Start P2Pool with the following command/options:
|
||||
|
||||
9. Start P2Pool with the following command/options:
|
||||
```
|
||||
.\p2pool.exe --host 127.0.0.1 --wallet YOUR_WALLET_ADDRESS
|
||||
.\p2pool.exe --host 127.0.0.1 --wallet YOUR_WALLET_ADDRESS --mini
|
||||
```
|
||||
9. Wait until the initial P2Pool sync is finished (shouldn't take more than 5-10 minutes).
|
||||
10. Start XMRig with the following command/options:
|
||||
10. Wait until the initial P2Pool sync is finished (shouldn't take more than 5-10 minutes).
|
||||
11. Start XMRig with the following command/options:
|
||||
```
|
||||
.\xmrig.exe -o 127.0.0.1:3333
|
||||
```
|
||||
@@ -179,17 +185,17 @@ nocreate
|
||||
```
|
||||
xmrig.exe -u x+10000 -o 127.0.0.1:3333
|
||||
```
|
||||
11. XMRig should connect and start mining!
|
||||
12. *(Optional but highly recommended)* You can create a Quickstart by creating a batch (.bat) file with the following contents and placing it in your P2Pool directory along with `xmrig.exe`.
|
||||
12. XMRig should connect and start mining!
|
||||
13. *(Optional but highly recommended)* You can create a Quickstart by creating a batch (.bat) file with the following contents and placing it in your P2Pool directory along with `xmrig.exe`.
|
||||
```
|
||||
@ECHO OFF
|
||||
start cmd /k %~dp0\Monero\monerod.exe --zmq-pub tcp://127.0.0.1:18083 --disable-dns-checkpoints --enable-dns-blocklist
|
||||
ECHO Wait until the Monero daemon shows fully synced before continuing. This can take some time. Type 'status' in other window to check progress.
|
||||
PAUSE
|
||||
start cmd /k %~dp0\p2pool.exe --wallet YOUR_WALLET_ADDRESS
|
||||
start cmd /k %~dp0\p2pool.exe --wallet YOUR_WALLET_ADDRESS --mini
|
||||
ECHO Wait until the daemon shows fully synced before continuing. This can take some time.
|
||||
PAUSE
|
||||
%~dp0\xmrig.exe -u x+30000 -o 127.0.0.1
|
||||
%~dp0\xmrig.exe -o 127.0.0.1
|
||||
```
|
||||
|
||||
## Build instructions
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
endif()
|
||||
endif()
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
set(GENERAL_FLAGS "")
|
||||
set(GENERAL_FLAGS "/MP")
|
||||
set(WARNING_FLAGS "/Wall /WX /sdl")
|
||||
set(SECURITY_FLAGS "/GS /guard:cf")
|
||||
set(OPTIMIZATION_FLAGS "/O2 /Oi /Ob2 /Ot /DNDEBUG /GL")
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
--rpc-login Specify username[:password] required for Monero RPC server
|
||||
--socks5 Specify IP:port of a SOCKS5 proxy to use for outgoing connections
|
||||
--no-dns disable DNS queries, use only IP addresses to connect to peers (seed node DNS will be unavailable too)
|
||||
--p2p-external-port port number that your router uses for mapping to your local p2p port. Use it if you are behind a NAT and still want to accept incoming connections
|
||||
```
|
||||
|
||||
### Example command line
|
||||
|
||||
Vendored
+1
-1
Submodule external/src/RandomX updated: b39068f7c3...d10edcbc93
+7
-4
@@ -165,8 +165,11 @@ BlockCache::~BlockCache()
|
||||
|
||||
void BlockCache::store(const PoolBlock& block)
|
||||
{
|
||||
const size_t n1 = block.m_mainChainData.size();
|
||||
const size_t n2 = block.m_sideChainData.size();
|
||||
const std::vector<uint8_t> mainchain_data = block.serialize_mainchain_data();
|
||||
const std::vector<uint8_t> sidechain_data = block.serialize_sidechain_data();
|
||||
|
||||
const size_t n1 = mainchain_data.size();
|
||||
const size_t n2 = sidechain_data.size();
|
||||
|
||||
if (!m_impl->m_data || (sizeof(uint32_t) + n1 + n2 > BLOCK_SIZE)) {
|
||||
return;
|
||||
@@ -175,8 +178,8 @@ void BlockCache::store(const PoolBlock& block)
|
||||
uint8_t* data = m_impl->m_data + (static_cast<size_t>((m_storeIndex++) % NUM_BLOCKS) * BLOCK_SIZE);
|
||||
|
||||
*reinterpret_cast<uint32_t*>(data) = static_cast<uint32_t>(n1 + n2);
|
||||
memcpy(data + sizeof(uint32_t), block.m_mainChainData.data(), n1);
|
||||
memcpy(data + sizeof(uint32_t) + n1, block.m_sideChainData.data(), n2);
|
||||
memcpy(data + sizeof(uint32_t), mainchain_data.data(), n1);
|
||||
memcpy(data + sizeof(uint32_t) + n1, sidechain_data.data(), n2);
|
||||
}
|
||||
|
||||
void BlockCache::load_all(SideChain& side_chain, P2PServer& server)
|
||||
|
||||
+43
-22
@@ -54,7 +54,11 @@ BlockTemplate::BlockTemplate(p2pool* pool)
|
||||
, m_txkeySec{}
|
||||
, m_poolBlockTemplate(new PoolBlock())
|
||||
, m_finalReward(0)
|
||||
, m_rng(RandomDeviceSeed::instance)
|
||||
{
|
||||
// Diffuse the initial state in case it has low quality
|
||||
m_rng.discard(10000);
|
||||
|
||||
uv_rwlock_init_checked(&m_lock);
|
||||
|
||||
m_blockHeader.reserve(64);
|
||||
@@ -133,6 +137,8 @@ BlockTemplate& BlockTemplate::operator=(const BlockTemplate& b)
|
||||
m_mempoolTxsOrder.clear();
|
||||
m_shares.clear();
|
||||
|
||||
m_rng = b.m_rng;
|
||||
|
||||
#if TEST_MEMPOOL_PICKING_ALGORITHM
|
||||
m_knapsack.clear();
|
||||
#endif
|
||||
@@ -171,6 +177,14 @@ static FORCEINLINE uint64_t get_block_reward(uint64_t base_reward, uint64_t medi
|
||||
return reward + fees;
|
||||
}
|
||||
|
||||
void BlockTemplate::shuffle_tx_order()
|
||||
{
|
||||
const int64_t n = static_cast<int64_t>(m_mempoolTxsOrder.size());
|
||||
for (int64_t i = n - 1; i > 0; --i) {
|
||||
std::swap(m_mempoolTxsOrder[i], m_mempoolTxsOrder[m_rng() % (i + 1)]);
|
||||
}
|
||||
}
|
||||
|
||||
void BlockTemplate::update(const MinerData& data, const Mempool& mempool, Wallet* miner_wallet)
|
||||
{
|
||||
if (data.major_version > HARDFORK_SUPPORTED_VERSION) {
|
||||
@@ -315,16 +329,16 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, Wallet
|
||||
|
||||
// if a block doesn't get into the penalty zone, just pick all transactions
|
||||
if (total_tx_weight + miner_tx_weight <= data.median_weight) {
|
||||
m_numTransactionHashes = 0;
|
||||
|
||||
final_fees = 0;
|
||||
final_weight = miner_tx_weight;
|
||||
|
||||
m_transactionHashes.assign(HASH_SIZE, 0);
|
||||
for (const TxMempoolData& tx : m_mempoolTxs) {
|
||||
m_transactionHashes.insert(m_transactionHashes.end(), tx.id.h, tx.id.h + HASH_SIZE);
|
||||
++m_numTransactionHashes;
|
||||
shuffle_tx_order();
|
||||
|
||||
m_numTransactionHashes = m_mempoolTxsOrder.size();
|
||||
m_transactionHashes.assign(HASH_SIZE, 0);
|
||||
for (size_t i = 0; i < m_mempoolTxsOrder.size(); ++i) {
|
||||
const TxMempoolData& tx = m_mempoolTxs[m_mempoolTxsOrder[i]];
|
||||
m_transactionHashes.insert(m_transactionHashes.end(), tx.id.h, tx.id.h + HASH_SIZE);
|
||||
final_fees += tx.fee;
|
||||
final_weight += tx.weight;
|
||||
}
|
||||
@@ -398,6 +412,8 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, Wallet
|
||||
final_fees = 0;
|
||||
final_weight = miner_tx_weight;
|
||||
|
||||
shuffle_tx_order();
|
||||
|
||||
m_numTransactionHashes = m_mempoolTxsOrder.size();
|
||||
m_transactionHashes.assign(HASH_SIZE, 0);
|
||||
for (size_t i = 0; i < m_mempoolTxsOrder.size(); ++i) {
|
||||
@@ -528,15 +544,16 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, Wallet
|
||||
memcpy(m_blockTemplateBlob.data() + sidechain_hash_offset, m_poolBlockTemplate->m_sidechainId.h, HASH_SIZE);
|
||||
memcpy(m_minerTx.data() + sidechain_hash_offset - m_minerTxOffsetInTemplate, m_poolBlockTemplate->m_sidechainId.h, HASH_SIZE);
|
||||
|
||||
m_poolBlockTemplate->serialize_mainchain_data(0, 0, m_poolBlockTemplate->m_sidechainId);
|
||||
|
||||
#if POOL_BLOCK_DEBUG
|
||||
if (m_poolBlockTemplate->m_mainChainData != m_blockTemplateBlob) {
|
||||
const std::vector<uint8_t> mainchain_data = m_poolBlockTemplate->serialize_mainchain_data();
|
||||
const std::vector<uint8_t> sidechain_data = m_poolBlockTemplate->serialize_sidechain_data();
|
||||
|
||||
if (mainchain_data != m_blockTemplateBlob) {
|
||||
LOGERR(1, "serialize_mainchain_data() has a bug, fix it! ");
|
||||
LOGERR(1, "m_poolBlockTemplate->m_mainChainData.size() = " << m_poolBlockTemplate->m_mainChainData.size());
|
||||
LOGERR(1, "m_poolBlockTemplate->m_mainChainData.size() = " << mainchain_data.size());
|
||||
LOGERR(1, "m_blockTemplateBlob.size() = " << m_blockTemplateBlob.size());
|
||||
for (size_t i = 0, n = std::min(m_poolBlockTemplate->m_mainChainData.size(), m_blockTemplateBlob.size()); i < n; ++i) {
|
||||
if (m_poolBlockTemplate->m_mainChainData[i] != m_blockTemplateBlob[i]) {
|
||||
for (size_t i = 0, n = std::min(mainchain_data.size(), m_blockTemplateBlob.size()); i < n; ++i) {
|
||||
if (mainchain_data[i] != m_blockTemplateBlob[i]) {
|
||||
LOGERR(1, "m_poolBlockTemplate->m_mainChainData is different at offset " << i);
|
||||
break;
|
||||
}
|
||||
@@ -545,7 +562,7 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, Wallet
|
||||
|
||||
{
|
||||
std::vector<uint8_t> buf = m_blockTemplateBlob;
|
||||
buf.insert(buf.end(), m_poolBlockTemplate->m_sideChainData.begin(), m_poolBlockTemplate->m_sideChainData.end());
|
||||
buf.insert(buf.end(), sidechain_data.begin(), sidechain_data.end());
|
||||
|
||||
PoolBlock check;
|
||||
const int result = check.deserialize(buf.data(), buf.size(), m_pool->side_chain(), nullptr);
|
||||
@@ -712,7 +729,7 @@ int BlockTemplate::create_miner_tx(const MinerData& data, const std::vector<Mine
|
||||
LOGERR(1, "get_eph_public_key failed at index " << i);
|
||||
}
|
||||
m_minerTx.insert(m_minerTx.end(), eph_public_key.h, eph_public_key.h + HASH_SIZE);
|
||||
m_poolBlockTemplate->m_outputs.emplace_back(m_rewards[i], eph_public_key, tx_type, view_tag);
|
||||
m_poolBlockTemplate->m_outputs.emplace_back(m_rewards[i], eph_public_key, view_tag);
|
||||
}
|
||||
|
||||
if (tx_type == TXOUT_TO_TAGGED_KEY) {
|
||||
@@ -784,8 +801,9 @@ hash BlockTemplate::calc_sidechain_hash() const
|
||||
const int blob_size = static_cast<int>(m_blockTemplateBlob.size());
|
||||
|
||||
const std::vector<uint8_t>& consensus_id = m_pool->side_chain().consensus_id();
|
||||
const std::vector<uint8_t> sidechain_data = m_poolBlockTemplate->serialize_sidechain_data();
|
||||
|
||||
keccak_custom([this, sidechain_hash_offset, blob_size, consensus_id](int offset) -> uint8_t {
|
||||
keccak_custom([this, sidechain_hash_offset, blob_size, consensus_id, &sidechain_data](int offset) -> uint8_t {
|
||||
uint32_t k = static_cast<uint32_t>(offset - static_cast<int>(m_nonceOffset));
|
||||
if (k < NONCE_SIZE) {
|
||||
return 0;
|
||||
@@ -806,15 +824,15 @@ hash BlockTemplate::calc_sidechain_hash() const
|
||||
}
|
||||
|
||||
const int side_chain_data_offsset = offset - blob_size;
|
||||
const int side_chain_data_size = static_cast<int>(m_poolBlockTemplate->m_sideChainData.size());
|
||||
const int side_chain_data_size = static_cast<int>(sidechain_data.size());
|
||||
if (side_chain_data_offsset < side_chain_data_size) {
|
||||
return m_poolBlockTemplate->m_sideChainData[side_chain_data_offsset];
|
||||
return sidechain_data[side_chain_data_offsset];
|
||||
}
|
||||
|
||||
const int consensus_id_offset = side_chain_data_offsset - side_chain_data_size;
|
||||
return consensus_id[consensus_id_offset];
|
||||
},
|
||||
static_cast<int>(m_blockTemplateBlob.size() + m_poolBlockTemplate->m_sideChainData.size() + consensus_id.size()), sidechain_hash.h, HASH_SIZE);
|
||||
static_cast<int>(m_blockTemplateBlob.size() + sidechain_data.size() + consensus_id.size()), sidechain_hash.h, HASH_SIZE);
|
||||
|
||||
return sidechain_hash;
|
||||
}
|
||||
@@ -1067,15 +1085,18 @@ void BlockTemplate::submit_sidechain_block(uint32_t template_id, uint32_t nonce,
|
||||
if (template_id == m_templateId) {
|
||||
m_poolBlockTemplate->m_nonce = nonce;
|
||||
m_poolBlockTemplate->m_extraNonce = extra_nonce;
|
||||
memcpy(m_poolBlockTemplate->m_mainChainData.data() + m_nonceOffset, &nonce, NONCE_SIZE);
|
||||
memcpy(m_poolBlockTemplate->m_mainChainData.data() + m_extraNonceOffsetInTemplate, &extra_nonce, EXTRA_NONCE_SIZE);
|
||||
|
||||
SideChain& side_chain = m_pool->side_chain();
|
||||
|
||||
#if POOL_BLOCK_DEBUG
|
||||
{
|
||||
std::vector<uint8_t> buf = m_poolBlockTemplate->m_mainChainData;
|
||||
buf.insert(buf.end(), m_poolBlockTemplate->m_sideChainData.begin(), m_poolBlockTemplate->m_sideChainData.end());
|
||||
std::vector<uint8_t> buf = m_poolBlockTemplate->serialize_mainchain_data();
|
||||
const std::vector<uint8_t> sidechain_data = m_poolBlockTemplate->serialize_sidechain_data();
|
||||
|
||||
memcpy(buf.data() + m_nonceOffset, &nonce, NONCE_SIZE);
|
||||
memcpy(buf.data() + m_extraNonceOffsetInTemplate, &extra_nonce, EXTRA_NONCE_SIZE);
|
||||
|
||||
buf.insert(buf.end(), sidechain_data.begin(), sidechain_data.end());
|
||||
|
||||
PoolBlock check;
|
||||
const int result = check.deserialize(buf.data(), buf.size(), side_chain, nullptr);
|
||||
|
||||
@@ -106,6 +106,10 @@ private:
|
||||
std::vector<int> m_mempoolTxsOrder;
|
||||
std::vector<MinerShare> m_shares;
|
||||
|
||||
std::mt19937_64 m_rng;
|
||||
|
||||
void shuffle_tx_order();
|
||||
|
||||
#if TEST_MEMPOOL_PICKING_ALGORITHM
|
||||
void fill_optimal_knapsack(const MinerData& data, uint64_t base_reward, uint64_t miner_tx_weight, uint64_t& best_reward, uint64_t& final_fees, uint64_t& final_weight);
|
||||
|
||||
|
||||
@@ -81,6 +81,14 @@
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef __has_feature
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
#if defined(_DEBUG) || defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) || defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)
|
||||
#define P2POOL_DEBUGGING 1
|
||||
#endif
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
constexpr size_t HASH_SIZE = 32;
|
||||
|
||||
+42
-17
@@ -154,10 +154,13 @@ static FORCEINLINE void derivation_to_scalar(const hash& derivation, size_t outp
|
||||
hash_to_scalar(data, static_cast<int>(p - data), res);
|
||||
}
|
||||
|
||||
class Cache
|
||||
class Cache : public nocopy_nomove
|
||||
{
|
||||
public:
|
||||
Cache()
|
||||
: derivations(new DerivationsMap())
|
||||
, public_keys(new PublicKeysMap())
|
||||
, tx_keys(new TxKeysMap())
|
||||
{
|
||||
uv_rwlock_init_checked(&derivations_lock);
|
||||
uv_rwlock_init_checked(&public_keys_lock);
|
||||
@@ -166,6 +169,10 @@ public:
|
||||
|
||||
~Cache()
|
||||
{
|
||||
delete derivations;
|
||||
delete public_keys;
|
||||
delete tx_keys;
|
||||
|
||||
uv_rwlock_destroy(&derivations_lock);
|
||||
uv_rwlock_destroy(&public_keys_lock);
|
||||
uv_rwlock_destroy(&tx_keys_lock);
|
||||
@@ -180,8 +187,8 @@ public:
|
||||
derivation = {};
|
||||
{
|
||||
ReadLock lock(derivations_lock);
|
||||
auto it = derivations.find(index);
|
||||
if (it != derivations.end()) {
|
||||
auto it = derivations->find(index);
|
||||
if (it != derivations->end()) {
|
||||
const DerivationEntry& entry = it->second;
|
||||
derivation = entry.m_derivation;
|
||||
if (entry.find_view_tag(output_index, view_tag)) {
|
||||
@@ -210,7 +217,7 @@ public:
|
||||
{
|
||||
WriteLock lock(derivations_lock);
|
||||
|
||||
DerivationEntry& entry = derivations.emplace(index, DerivationEntry{ derivation, {} }).first->second;
|
||||
DerivationEntry& entry = derivations->emplace(index, DerivationEntry{ derivation, {} }).first->second;
|
||||
|
||||
const uint32_t k = static_cast<uint32_t>(output_index << 8) | view_tag;
|
||||
if (std::find(entry.m_viewTags.begin(), entry.m_viewTags.end(), k) == entry.m_viewTags.end()) {
|
||||
@@ -230,8 +237,8 @@ public:
|
||||
|
||||
{
|
||||
ReadLock lock(public_keys_lock);
|
||||
auto it = public_keys.find(index);
|
||||
if (it != public_keys.end()) {
|
||||
auto it = public_keys->find(index);
|
||||
if (it != public_keys->end()) {
|
||||
derived_key = it->second;
|
||||
return true;
|
||||
}
|
||||
@@ -257,7 +264,7 @@ public:
|
||||
|
||||
{
|
||||
WriteLock lock(public_keys_lock);
|
||||
public_keys.emplace(index, derived_key);
|
||||
public_keys->emplace(index, derived_key);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -271,8 +278,8 @@ public:
|
||||
|
||||
{
|
||||
ReadLock lock(tx_keys_lock);
|
||||
auto it = tx_keys.find(index);
|
||||
if (it != tx_keys.end()) {
|
||||
auto it = tx_keys->find(index);
|
||||
if (it != tx_keys->end()) {
|
||||
pub = it->second.first;
|
||||
sec = it->second.second;
|
||||
return;
|
||||
@@ -291,15 +298,27 @@ public:
|
||||
|
||||
{
|
||||
WriteLock lock(tx_keys_lock);
|
||||
tx_keys.emplace(index, std::pair<hash, hash>(pub, sec));
|
||||
tx_keys->emplace(index, std::pair<hash, hash>(pub, sec));
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
{ WriteLock lock(derivations_lock); derivations.clear(); }
|
||||
{ WriteLock lock(public_keys_lock); public_keys.clear(); }
|
||||
{ WriteLock lock(tx_keys_lock); tx_keys.clear(); }
|
||||
{
|
||||
WriteLock lock(derivations_lock);
|
||||
delete derivations;
|
||||
derivations = new DerivationsMap();
|
||||
}
|
||||
{
|
||||
WriteLock lock(public_keys_lock);
|
||||
delete public_keys;
|
||||
public_keys = new PublicKeysMap();
|
||||
}
|
||||
{
|
||||
WriteLock lock(tx_keys_lock);
|
||||
delete tx_keys;
|
||||
tx_keys = new TxKeysMap();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -319,14 +338,18 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
typedef unordered_map<std::array<uint8_t, HASH_SIZE * 2>, DerivationEntry> DerivationsMap;
|
||||
typedef unordered_map<std::array<uint8_t, HASH_SIZE * 2 + sizeof(size_t)>, hash> PublicKeysMap;
|
||||
typedef unordered_map<std::array<uint8_t, HASH_SIZE * 2>, std::pair<hash, hash>> TxKeysMap;
|
||||
|
||||
uv_rwlock_t derivations_lock;
|
||||
unordered_map<std::array<uint8_t, HASH_SIZE * 2>, DerivationEntry> derivations;
|
||||
DerivationsMap* derivations;
|
||||
|
||||
uv_rwlock_t public_keys_lock;
|
||||
unordered_map<std::array<uint8_t, HASH_SIZE * 2 + sizeof(size_t)>, hash> public_keys;
|
||||
PublicKeysMap* public_keys;
|
||||
|
||||
uv_rwlock_t tx_keys_lock;
|
||||
unordered_map<std::array<uint8_t, HASH_SIZE * 2>, std::pair<hash, hash>> tx_keys;
|
||||
TxKeysMap* tx_keys;
|
||||
};
|
||||
|
||||
static Cache* cache = nullptr;
|
||||
@@ -379,7 +402,9 @@ void destroy_crypto_cache()
|
||||
|
||||
void clear_crypto_cache()
|
||||
{
|
||||
cache->clear();
|
||||
if (cache) {
|
||||
cache->clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
@@ -50,6 +50,7 @@ void p2pool_usage()
|
||||
"--rpc-login Specify username[:password] required for Monero RPC server\n"
|
||||
"--socks5 Specify IP:port of a SOCKS5 proxy to use for outgoing connections\n"
|
||||
"--no-dns disable DNS queries, use only IP addresses to connect to peers (seed node DNS will be unavailable too)\n"
|
||||
"--p2p-external-port port number that your router uses for mapping to your local p2p port. Use it if you are behind a NAT and still want to accept incoming connections\n"
|
||||
"--help Show this help message\n\n"
|
||||
"Example command line:\n\n"
|
||||
"%s --host 127.0.0.1 --rpc-port 18081 --zmq-port 18083 --wallet YOUR_WALLET_ADDRESS --stratum 0.0.0.0:%d --p2p 0.0.0.0:%d\n\n",
|
||||
|
||||
+92
-32
@@ -32,15 +32,48 @@ namespace p2pool {
|
||||
|
||||
static bool track_memory = false;
|
||||
|
||||
constexpr size_t N = 2097152;
|
||||
constexpr size_t MAX_FRAMES = 30;
|
||||
constexpr size_t N = 1 << 22;
|
||||
constexpr size_t MAX_FRAMES = 29;
|
||||
|
||||
struct TrackedAllocation
|
||||
{
|
||||
void* p;
|
||||
void* stack_trace[MAX_FRAMES];
|
||||
uint64_t allocated_size;
|
||||
uint32_t thread_id;
|
||||
uint32_t allocated_size;
|
||||
|
||||
FORCEINLINE bool operator<(const TrackedAllocation& rhs) { return memcmp(stack_trace, rhs.stack_trace, sizeof(stack_trace)) < 0; }
|
||||
FORCEINLINE bool operator==(const TrackedAllocation& rhs) { return memcmp(stack_trace, rhs.stack_trace, sizeof(stack_trace)) == 0; }
|
||||
|
||||
void print(HANDLE h) const
|
||||
{
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)] = {};
|
||||
PSYMBOL_INFO pSymbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
|
||||
|
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
pSymbol->MaxNameLen = MAX_SYM_NAME;
|
||||
|
||||
IMAGEHLP_LINE64 line{};
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
|
||||
for (size_t j = 0; j < MAX_FRAMES; ++j) {
|
||||
const DWORD64 address = reinterpret_cast<DWORD64>(stack_trace[j]);
|
||||
DWORD64 t1 = 0;
|
||||
DWORD t2 = 0;
|
||||
if (SymFromAddr(h, address, &t1, pSymbol) && SymGetLineFromAddr64(h, address, &t2, &line)) {
|
||||
const char* s = line.FileName;
|
||||
const char* file_name = nullptr;
|
||||
while (*s) {
|
||||
if ((*s == '\\') || (*s == '/')) {
|
||||
file_name = s + 1;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
printf("%-25s %s (line %lu)\n", file_name ? file_name : line.FileName, pSymbol->Name, line.LineNumber);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(TrackedAllocation) == 256, "");
|
||||
@@ -51,15 +84,62 @@ uint32_t first[N];
|
||||
uint32_t next[N];
|
||||
TrackedAllocation allocations[N];
|
||||
uint32_t num_allocations = 0;
|
||||
uint64_t total_allocated = 0;
|
||||
uint32_t cur_allocation_index = 1;
|
||||
|
||||
void show_top_10()
|
||||
{
|
||||
TrackedAllocation* buf = reinterpret_cast<TrackedAllocation*>(VirtualAlloc(nullptr, sizeof(TrackedAllocation) * N, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
|
||||
if (!buf) {
|
||||
return;
|
||||
}
|
||||
|
||||
const HANDLE h = GetCurrentProcess();
|
||||
|
||||
{
|
||||
p2pool::MutexLock lock(allocation_lock);
|
||||
|
||||
TrackedAllocation* end = buf;
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (allocations[i].allocated_size) {
|
||||
*(end++) = allocations[i];
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(buf, end);
|
||||
|
||||
TrackedAllocation* prev = buf;
|
||||
for (TrackedAllocation* p = buf + 1; p < end; ++p) {
|
||||
if (*p == *prev) {
|
||||
prev->allocated_size += p->allocated_size;
|
||||
}
|
||||
else {
|
||||
++prev;
|
||||
*prev = *p;
|
||||
}
|
||||
}
|
||||
end = prev + 1;
|
||||
|
||||
std::sort(buf, end, [](const auto& a, const auto& b) { return a.allocated_size > b.allocated_size; });
|
||||
|
||||
printf("%I64u total bytes allocated\n", total_allocated);
|
||||
|
||||
for (TrackedAllocation* p = buf; (p < buf + 10) && (p < end); ++p) {
|
||||
printf("%I64u bytes allocated at:\n", p->allocated_size);
|
||||
p->print(h);
|
||||
}
|
||||
}
|
||||
|
||||
VirtualFree(buf, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
FORCEINLINE static void add_alocation(void* p, size_t size)
|
||||
{
|
||||
if (!track_memory) {
|
||||
return;
|
||||
}
|
||||
|
||||
void* stack_trace[MAX_FRAMES];
|
||||
void* stack_trace[MAX_FRAMES] = {};
|
||||
DWORD hash;
|
||||
CaptureStackBackTrace(1, MAX_FRAMES, stack_trace, &hash);
|
||||
|
||||
@@ -74,6 +154,7 @@ FORCEINLINE static void add_alocation(void* p, size_t size)
|
||||
// Make N two times bigger if this triggers
|
||||
__debugbreak();
|
||||
}
|
||||
total_allocated += size;
|
||||
|
||||
for (uint64_t i = cur_allocation_index;; i = (i + 1) & (N - 1)) {
|
||||
if (i && !allocations[i].allocated_size) {
|
||||
@@ -105,6 +186,7 @@ FORCEINLINE static void remove_allocation(void* p)
|
||||
|
||||
for (uint32_t prev = 0, k = first[index]; k != 0; prev = k, k = next[k]) {
|
||||
if (allocations[k].p == p) {
|
||||
total_allocated -= allocations[k].allocated_size;
|
||||
allocations[k].allocated_size = 0;
|
||||
if (prev) {
|
||||
next[prev] = next[k];
|
||||
@@ -181,6 +263,8 @@ void* calloc_hook(size_t count, size_t size) noexcept
|
||||
|
||||
void memory_tracking_start()
|
||||
{
|
||||
SymInitialize(GetCurrentProcess(), NULL, TRUE);
|
||||
|
||||
using namespace p2pool;
|
||||
|
||||
uv_replace_allocator(malloc_hook, realloc_hook, calloc_hook, free_hook);
|
||||
@@ -196,7 +280,6 @@ void memory_tracking_stop()
|
||||
uv_mutex_destroy(&allocation_lock);
|
||||
|
||||
const HANDLE h = GetCurrentProcess();
|
||||
SymInitialize(h, NULL, TRUE);
|
||||
|
||||
uint64_t total_leaks = 0;
|
||||
|
||||
@@ -205,39 +288,16 @@ void memory_tracking_stop()
|
||||
if (t.allocated_size) {
|
||||
total_leaks += t.allocated_size;
|
||||
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)] = {};
|
||||
PSYMBOL_INFO pSymbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
|
||||
|
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
pSymbol->MaxNameLen = MAX_SYM_NAME;
|
||||
|
||||
IMAGEHLP_LINE64 line{};
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
|
||||
printf("Memory leak detected, %u bytes allocated at %p by thread %u:\n", t.allocated_size, t.p, t.thread_id);
|
||||
for (size_t j = 0; j < MAX_FRAMES; ++j) {
|
||||
const DWORD64 address = reinterpret_cast<DWORD64>(t.stack_trace[j]);
|
||||
DWORD64 t1 = 0;
|
||||
DWORD t2 = 0;
|
||||
if (SymFromAddr(h, address, &t1, pSymbol) && SymGetLineFromAddr64(h, address, &t2, &line)) {
|
||||
const char* s = line.FileName;
|
||||
const char* file_name = nullptr;
|
||||
while (*s) {
|
||||
if ((*s == '\\') || (*s == '/')) {
|
||||
file_name = s + 1;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
printf("%-25s %s (line %lu)\n", file_name ? file_name : line.FileName, pSymbol->Name, line.LineNumber);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
printf("Memory leak detected, %I64u bytes allocated at %p by thread %u:\n", t.allocated_size, t.p, t.thread_id);
|
||||
t.print(h);
|
||||
}
|
||||
}
|
||||
|
||||
if (total_leaks > 0) {
|
||||
printf("%I64u bytes leaked\n\n", total_leaks);
|
||||
}
|
||||
|
||||
SymCleanup(h);
|
||||
}
|
||||
|
||||
NOINLINE void* operator new(size_t n) { return p2pool::allocate(n); }
|
||||
|
||||
+2
-1
@@ -25,6 +25,7 @@
|
||||
#include "params.h"
|
||||
#include "p2pool_api.h"
|
||||
#include "side_chain.h"
|
||||
#include "p2p_server.h"
|
||||
#include <thread>
|
||||
|
||||
static constexpr char log_category_prefix[] = "Miner ";
|
||||
@@ -40,7 +41,7 @@ Miner::Miner(p2pool* pool, uint32_t threads)
|
||||
, m_startTimestamp(high_resolution_clock::now())
|
||||
, m_nonce(0)
|
||||
, m_nonceTimestamp(m_startTimestamp)
|
||||
, m_extraNonce(0xF19E3779U)
|
||||
, m_extraNonce(static_cast<uint32_t>(pool->p2p_server()->get_random64()))
|
||||
, m_totalHashes(0)
|
||||
, m_sharesFound(0)
|
||||
, m_job{}
|
||||
|
||||
+27
-14
@@ -139,12 +139,6 @@ P2PServer::P2PServer(p2pool* pool)
|
||||
|
||||
P2PServer::~P2PServer()
|
||||
{
|
||||
uv_timer_stop(&m_timer);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_timer), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_broadcastAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_connectToPeersAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_showPeersAsync), nullptr);
|
||||
|
||||
shutdown_tcp();
|
||||
|
||||
uv_mutex_destroy(&m_rngLock);
|
||||
@@ -747,12 +741,16 @@ void P2PServer::broadcast(const PoolBlock& block)
|
||||
|
||||
Broadcast* data = new Broadcast();
|
||||
|
||||
data->blob.reserve(block.m_mainChainData.size() + block.m_sideChainData.size());
|
||||
data->blob = block.m_mainChainData;
|
||||
data->blob.insert(data->blob.end(), block.m_sideChainData.begin(), block.m_sideChainData.end());
|
||||
int outputs_offset, outputs_blob_size;
|
||||
const std::vector<uint8_t> mainchain_data = block.serialize_mainchain_data(nullptr, nullptr, &outputs_offset, &outputs_blob_size);
|
||||
const std::vector<uint8_t> sidechain_data = block.serialize_sidechain_data();
|
||||
|
||||
data->pruned_blob.reserve(block.m_mainChainData.size() + block.m_sideChainData.size() + 16 - block.m_mainChainOutputsBlobSize);
|
||||
data->pruned_blob.assign(block.m_mainChainData.begin(), block.m_mainChainData.begin() + block.m_mainChainOutputsOffset);
|
||||
data->blob.reserve(mainchain_data.size() + sidechain_data.size());
|
||||
data->blob = mainchain_data;
|
||||
data->blob.insert(data->blob.end(), sidechain_data.begin(), sidechain_data.end());
|
||||
|
||||
data->pruned_blob.reserve(mainchain_data.size() + sidechain_data.size() + 16 - outputs_blob_size);
|
||||
data->pruned_blob.assign(mainchain_data.begin(), mainchain_data.begin() + outputs_offset);
|
||||
|
||||
// 0 outputs in the pruned blob
|
||||
data->pruned_blob.push_back(0);
|
||||
@@ -764,10 +762,10 @@ void P2PServer::broadcast(const PoolBlock& block)
|
||||
});
|
||||
|
||||
writeVarint(total_reward, data->pruned_blob);
|
||||
writeVarint(block.m_mainChainOutputsBlobSize, data->pruned_blob);
|
||||
writeVarint(outputs_blob_size, data->pruned_blob);
|
||||
|
||||
data->pruned_blob.insert(data->pruned_blob.end(), block.m_mainChainData.begin() + block.m_mainChainOutputsOffset + block.m_mainChainOutputsBlobSize, block.m_mainChainData.end());
|
||||
data->pruned_blob.insert(data->pruned_blob.end(), block.m_sideChainData.begin(), block.m_sideChainData.end());
|
||||
data->pruned_blob.insert(data->pruned_blob.end(), mainchain_data.begin() + outputs_offset + outputs_blob_size, mainchain_data.end());
|
||||
data->pruned_blob.insert(data->pruned_blob.end(), sidechain_data.begin(), sidechain_data.end());
|
||||
|
||||
data->ancestor_hashes.reserve(block.m_uncles.size() + 1);
|
||||
data->ancestor_hashes = block.m_uncles;
|
||||
@@ -935,6 +933,12 @@ void P2PServer::show_peers()
|
||||
LOGINFO(0, "Total: " << n << " peers");
|
||||
}
|
||||
|
||||
int P2PServer::listen_port() const
|
||||
{
|
||||
const Params& params = m_pool->params();
|
||||
return params.m_p2pExternalPort ? params.m_p2pExternalPort : m_listenPort;
|
||||
}
|
||||
|
||||
int P2PServer::deserialize_block(const uint8_t* buf, uint32_t size)
|
||||
{
|
||||
int result;
|
||||
@@ -1125,6 +1129,15 @@ P2PServer::P2PClient::P2PClient()
|
||||
{
|
||||
}
|
||||
|
||||
void P2PServer::on_shutdown()
|
||||
{
|
||||
uv_timer_stop(&m_timer);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_timer), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_broadcastAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_connectToPeersAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_showPeersAsync), nullptr);
|
||||
}
|
||||
|
||||
P2PServer::P2PClient::~P2PClient()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -138,6 +138,8 @@ public:
|
||||
void show_peers_async();
|
||||
size_t peer_list_size() const { MutexLock lock(m_peerListLock); return m_peerList.size(); }
|
||||
|
||||
int listen_port() const override;
|
||||
|
||||
uint32_t max_outgoing_peers() const { return m_maxOutgoingPeers; }
|
||||
uint32_t max_incoming_peers() const { return m_maxIncomingPeers; }
|
||||
|
||||
@@ -234,6 +236,8 @@ private:
|
||||
|
||||
static void on_show_peers(uv_async_t* handle) { reinterpret_cast<P2PServer*>(handle->data)->show_peers(); }
|
||||
void show_peers();
|
||||
|
||||
void on_shutdown() override;
|
||||
};
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
+11
-8
@@ -301,6 +301,11 @@ void p2pool::handle_miner_data(MinerData& data)
|
||||
"\n---------------------------------------------------------------------------------------------------------------"
|
||||
);
|
||||
|
||||
// Tx secret keys from all miners change every block, so cache can be cleared here
|
||||
if (m_sideChain->precalcFinished()) {
|
||||
clear_crypto_cache();
|
||||
}
|
||||
|
||||
if (!is_main_thread()) {
|
||||
update_block_template_async();
|
||||
}
|
||||
@@ -404,7 +409,7 @@ void p2pool::handle_chain_main(ChainMain& data, const char* extra)
|
||||
if (payout) {
|
||||
LOGINFO(0, log::LightCyan() << "You received a payout of " << log::LightGreen() << log::XMRAmount(payout) << log::LightCyan() << " in block " << log::LightGreen() << data.height);
|
||||
}
|
||||
api_update_block_found(&data);
|
||||
api_update_block_found(&data, block);
|
||||
}
|
||||
else {
|
||||
side_chain().watch_mainchain_block(data, sidechain_id);
|
||||
@@ -440,7 +445,7 @@ void p2pool::submit_block_async(uint32_t template_id, uint32_t nonce, uint32_t e
|
||||
}
|
||||
}
|
||||
|
||||
void p2pool::submit_block_async(const std::vector<uint8_t>& blob)
|
||||
void p2pool::submit_block_async(std::vector<uint8_t>&& blob)
|
||||
{
|
||||
{
|
||||
MutexLock lock(m_submitBlockDataLock);
|
||||
@@ -448,7 +453,7 @@ void p2pool::submit_block_async(const std::vector<uint8_t>& blob)
|
||||
m_submitBlockData.template_id = 0;
|
||||
m_submitBlockData.nonce = 0;
|
||||
m_submitBlockData.extra_nonce = 0;
|
||||
m_submitBlockData.blob = blob;
|
||||
m_submitBlockData.blob = std::move(blob);
|
||||
}
|
||||
|
||||
// If p2pool is stopped, m_submitBlockAsync is most likely already closed
|
||||
@@ -850,7 +855,7 @@ void p2pool::load_found_blocks()
|
||||
m_foundBlocks.emplace_back(timestamp, height, id, block_difficulty, cumulative_difficulty);
|
||||
}
|
||||
|
||||
api_update_block_found(nullptr);
|
||||
api_update_block_found(nullptr, nullptr);
|
||||
}
|
||||
|
||||
void p2pool::parse_get_info_rpc(const char* data, size_t size)
|
||||
@@ -1320,16 +1325,14 @@ void p2pool::cleanup_mainchain_data(uint64_t height)
|
||||
}
|
||||
}
|
||||
|
||||
void p2pool::api_update_block_found(const ChainMain* data)
|
||||
void p2pool::api_update_block_found(const ChainMain* data, const PoolBlock* block)
|
||||
{
|
||||
clear_crypto_cache();
|
||||
|
||||
if (!m_api) {
|
||||
return;
|
||||
}
|
||||
|
||||
const time_t cur_time = time(nullptr);
|
||||
const difficulty_type total_hashes = m_sideChain->total_hashes();
|
||||
const difficulty_type total_hashes = block ? block->m_cumulativeDifficulty : m_sideChain->total_hashes();
|
||||
difficulty_type diff;
|
||||
|
||||
if (data && get_difficulty_at_height(data->height, diff)) {
|
||||
|
||||
+3
-2
@@ -33,6 +33,7 @@ class Miner;
|
||||
class ConsoleCommands;
|
||||
class p2pool_api;
|
||||
class ZMQReader;
|
||||
struct PoolBlock;
|
||||
|
||||
class p2pool : public MinerCallbackHandler
|
||||
{
|
||||
@@ -74,7 +75,7 @@ public:
|
||||
virtual void handle_chain_main(ChainMain& data, const char* extra) override;
|
||||
|
||||
void submit_block_async(uint32_t template_id, uint32_t nonce, uint32_t extra_nonce);
|
||||
void submit_block_async(const std::vector<uint8_t>& blob);
|
||||
void submit_block_async(std::vector<uint8_t>&& blob);
|
||||
void submit_sidechain_block(uint32_t template_id, uint32_t nonce, uint32_t extra_nonce);
|
||||
|
||||
void update_block_template_async(bool is_alternative_block = false);
|
||||
@@ -84,7 +85,7 @@ public:
|
||||
|
||||
bool chainmain_get_by_hash(const hash& id, ChainMain& data) const;
|
||||
|
||||
void api_update_block_found(const ChainMain* data);
|
||||
void api_update_block_found(const ChainMain* data, const PoolBlock* block);
|
||||
|
||||
bool get_difficulty_at_height(uint64_t height, difficulty_type& diff);
|
||||
|
||||
|
||||
+7
-2
@@ -35,12 +35,12 @@ Params::Params(int argc, char* argv[])
|
||||
}
|
||||
|
||||
if ((strcmp(argv[i], "--rpc-port") == 0) && (i + 1 < argc)) {
|
||||
m_rpcPort = strtoul(argv[++i], nullptr, 10);
|
||||
m_rpcPort = std::min(std::max(strtoul(argv[++i], nullptr, 10), 1UL), 65535UL);
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if ((strcmp(argv[i], "--zmq-port") == 0) && (i + 1 < argc)) {
|
||||
m_zmqPort = strtoul(argv[++i], nullptr, 10);
|
||||
m_zmqPort = std::min(std::max(strtoul(argv[++i], nullptr, 10), 1UL), 65535UL);
|
||||
ok = true;
|
||||
}
|
||||
|
||||
@@ -146,6 +146,11 @@ Params::Params(int argc, char* argv[])
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if ((strcmp(argv[i], "--p2p-external-port") == 0) && (i + 1 < argc)) {
|
||||
m_p2pExternalPort = std::min(std::max(strtoul(argv[++i], nullptr, 10), 1UL), 65535UL);
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
fprintf(stderr, "Unknown command line parameter %s\n\n", argv[i]);
|
||||
p2pool_usage();
|
||||
|
||||
@@ -52,6 +52,7 @@ struct Params
|
||||
std::string m_rpcLogin;
|
||||
std::string m_socks5Proxy;
|
||||
bool m_dns = true;
|
||||
uint32_t m_p2pExternalPort = 0;
|
||||
};
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
+97
-68
@@ -29,11 +29,7 @@ static constexpr char log_category_prefix[] = "PoolBlock ";
|
||||
namespace p2pool {
|
||||
|
||||
PoolBlock::PoolBlock()
|
||||
: m_mainChainHeaderSize(0)
|
||||
, m_mainChainMinerTxSize(0)
|
||||
, m_mainChainOutputsOffset(0)
|
||||
, m_mainChainOutputsBlobSize(0)
|
||||
, m_majorVersion(0)
|
||||
: m_majorVersion(0)
|
||||
, m_minorVersion(0)
|
||||
, m_timestamp(0)
|
||||
, m_prevId{}
|
||||
@@ -57,12 +53,6 @@ PoolBlock::PoolBlock()
|
||||
, m_localTimestamp(seconds_since_epoch())
|
||||
{
|
||||
uv_mutex_init_checked(&m_lock);
|
||||
|
||||
m_mainChainData.reserve(48 * 1024);
|
||||
m_outputs.reserve(2048);
|
||||
m_transactions.reserve(256);
|
||||
m_sideChainData.reserve(512);
|
||||
m_uncles.reserve(8);
|
||||
}
|
||||
|
||||
PoolBlock::PoolBlock(const PoolBlock& b)
|
||||
@@ -83,11 +73,11 @@ PoolBlock& PoolBlock::operator=(const PoolBlock& b)
|
||||
LOGERR(1, "operator= uv_mutex_trylock failed. Fix the code!");
|
||||
}
|
||||
|
||||
m_mainChainData = b.m_mainChainData;
|
||||
m_mainChainHeaderSize = b.m_mainChainHeaderSize;
|
||||
m_mainChainMinerTxSize = b.m_mainChainMinerTxSize;
|
||||
m_mainChainOutputsOffset = b.m_mainChainOutputsOffset;
|
||||
m_mainChainOutputsBlobSize = b.m_mainChainOutputsBlobSize;
|
||||
#if POOL_BLOCK_DEBUG
|
||||
m_mainChainDataDebug = b.m_mainChainDataDebug;
|
||||
m_sideChainDataDebug = b.m_sideChainDataDebug;
|
||||
#endif
|
||||
|
||||
m_majorVersion = b.m_majorVersion;
|
||||
m_minorVersion = b.m_minorVersion;
|
||||
m_timestamp = b.m_timestamp;
|
||||
@@ -99,7 +89,6 @@ PoolBlock& PoolBlock::operator=(const PoolBlock& b)
|
||||
m_extraNonceSize = b.m_extraNonceSize;
|
||||
m_extraNonce = b.m_extraNonce;
|
||||
m_transactions = b.m_transactions;
|
||||
m_sideChainData = b.m_sideChainData;
|
||||
m_minerWallet = b.m_minerWallet;
|
||||
m_txkeySec = b.m_txkeySec;
|
||||
m_parent = b.m_parent;
|
||||
@@ -129,43 +118,58 @@ PoolBlock::~PoolBlock()
|
||||
uv_mutex_destroy(&m_lock);
|
||||
}
|
||||
|
||||
void PoolBlock::serialize_mainchain_data(uint32_t nonce, uint32_t extra_nonce, const hash& sidechain_hash)
|
||||
std::vector<uint8_t> PoolBlock::serialize_mainchain_data(size_t* header_size, size_t* miner_tx_size, int* outputs_offset, int* outputs_blob_size) const
|
||||
{
|
||||
MutexLock lock(m_lock);
|
||||
return serialize_mainchain_data_nolock(header_size, miner_tx_size, outputs_offset, outputs_blob_size);
|
||||
}
|
||||
|
||||
m_mainChainData.clear();
|
||||
std::vector<uint8_t> PoolBlock::serialize_mainchain_data_nolock(size_t* header_size, size_t* miner_tx_size, int* outputs_offset, int* outputs_blob_size) const
|
||||
{
|
||||
std::vector<uint8_t> data;
|
||||
data.reserve(128 + m_outputs.size() * 39 + m_transactions.size() * HASH_SIZE);
|
||||
|
||||
// Header
|
||||
m_mainChainData.push_back(m_majorVersion);
|
||||
m_mainChainData.push_back(m_minorVersion);
|
||||
writeVarint(m_timestamp, m_mainChainData);
|
||||
m_mainChainData.insert(m_mainChainData.end(), m_prevId.h, m_prevId.h + HASH_SIZE);
|
||||
m_mainChainData.insert(m_mainChainData.end(), reinterpret_cast<uint8_t*>(&nonce), reinterpret_cast<uint8_t*>(&nonce) + NONCE_SIZE);
|
||||
data.push_back(m_majorVersion);
|
||||
data.push_back(m_minorVersion);
|
||||
writeVarint(m_timestamp, data);
|
||||
data.insert(data.end(), m_prevId.h, m_prevId.h + HASH_SIZE);
|
||||
data.insert(data.end(), reinterpret_cast<const uint8_t*>(&m_nonce), reinterpret_cast<const uint8_t*>(&m_nonce) + NONCE_SIZE);
|
||||
|
||||
m_mainChainHeaderSize = m_mainChainData.size();
|
||||
const size_t header_size0 = data.size();
|
||||
if (header_size) {
|
||||
*header_size = header_size0;
|
||||
}
|
||||
|
||||
// Miner tx
|
||||
m_mainChainData.push_back(TX_VERSION);
|
||||
writeVarint(m_txinGenHeight + MINER_REWARD_UNLOCK_TIME, m_mainChainData);
|
||||
m_mainChainData.push_back(1);
|
||||
m_mainChainData.push_back(TXIN_GEN);
|
||||
writeVarint(m_txinGenHeight, m_mainChainData);
|
||||
data.push_back(TX_VERSION);
|
||||
writeVarint(m_txinGenHeight + MINER_REWARD_UNLOCK_TIME, data);
|
||||
data.push_back(1);
|
||||
data.push_back(TXIN_GEN);
|
||||
writeVarint(m_txinGenHeight, data);
|
||||
|
||||
m_mainChainOutputsOffset = static_cast<int>(m_mainChainData.size());
|
||||
const int outputs_offset0 = static_cast<int>(data.size());
|
||||
if (outputs_offset) {
|
||||
*outputs_offset = outputs_offset0;
|
||||
}
|
||||
|
||||
writeVarint(m_outputs.size(), m_mainChainData);
|
||||
writeVarint(m_outputs.size(), data);
|
||||
|
||||
for (TxOutput& output : m_outputs) {
|
||||
writeVarint(output.m_reward, m_mainChainData);
|
||||
m_mainChainData.push_back(output.m_txType);
|
||||
m_mainChainData.insert(m_mainChainData.end(), output.m_ephPublicKey.h, output.m_ephPublicKey.h + HASH_SIZE);
|
||||
const uint8_t tx_type = get_tx_type();
|
||||
|
||||
if (output.m_txType == TXOUT_TO_TAGGED_KEY) {
|
||||
m_mainChainData.push_back(output.m_viewTag);
|
||||
for (const TxOutput& output : m_outputs) {
|
||||
writeVarint(output.m_reward, data);
|
||||
data.push_back(tx_type);
|
||||
data.insert(data.end(), output.m_ephPublicKey.h, output.m_ephPublicKey.h + HASH_SIZE);
|
||||
|
||||
if (tx_type == TXOUT_TO_TAGGED_KEY) {
|
||||
data.push_back(static_cast<uint8_t>(output.m_viewTag));
|
||||
}
|
||||
}
|
||||
|
||||
m_mainChainOutputsBlobSize = static_cast<int>(m_mainChainData.size()) - m_mainChainOutputsOffset;
|
||||
if (outputs_blob_size) {
|
||||
*outputs_blob_size = static_cast<int>(data.size()) - outputs_offset0;
|
||||
}
|
||||
|
||||
uint8_t tx_extra[128];
|
||||
uint8_t* p = tx_extra;
|
||||
@@ -183,7 +187,6 @@ void PoolBlock::serialize_mainchain_data(uint32_t nonce, uint32_t extra_nonce, c
|
||||
*(p++) = TX_EXTRA_NONCE;
|
||||
*(p++) = static_cast<uint8_t>(extra_nonce_size);
|
||||
|
||||
m_extraNonce = extra_nonce;
|
||||
memcpy(p, &m_extraNonce, EXTRA_NONCE_SIZE);
|
||||
p += EXTRA_NONCE_SIZE;
|
||||
if (extra_nonce_size > EXTRA_NONCE_SIZE) {
|
||||
@@ -193,49 +196,70 @@ void PoolBlock::serialize_mainchain_data(uint32_t nonce, uint32_t extra_nonce, c
|
||||
|
||||
*(p++) = TX_EXTRA_MERGE_MINING_TAG;
|
||||
*(p++) = HASH_SIZE;
|
||||
memcpy(p, sidechain_hash.h, HASH_SIZE);
|
||||
memcpy(p, m_sidechainId.h, HASH_SIZE);
|
||||
p += HASH_SIZE;
|
||||
|
||||
writeVarint(static_cast<size_t>(p - tx_extra), m_mainChainData);
|
||||
m_mainChainData.insert(m_mainChainData.end(), tx_extra, p);
|
||||
writeVarint(static_cast<size_t>(p - tx_extra), data);
|
||||
data.insert(data.end(), tx_extra, p);
|
||||
|
||||
m_mainChainData.push_back(0);
|
||||
data.push_back(0);
|
||||
|
||||
m_mainChainMinerTxSize = m_mainChainData.size() - m_mainChainHeaderSize;
|
||||
if (miner_tx_size) {
|
||||
*miner_tx_size = data.size() - header_size0;
|
||||
}
|
||||
|
||||
writeVarint(m_transactions.size() - 1, m_mainChainData);
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(m_transactions.data());
|
||||
m_mainChainData.insert(m_mainChainData.end(), data + HASH_SIZE, data + m_transactions.size() * HASH_SIZE);
|
||||
writeVarint(m_transactions.size() - 1, data);
|
||||
const uint8_t* t = reinterpret_cast<const uint8_t*>(m_transactions.data());
|
||||
data.insert(data.end(), t + HASH_SIZE, t + m_transactions.size() * HASH_SIZE);
|
||||
|
||||
#if POOL_BLOCK_DEBUG
|
||||
if (!m_mainChainDataDebug.empty() && (data != m_mainChainDataDebug)) {
|
||||
LOGERR(1, "serialize_mainchain_data() has a bug, fix it!");
|
||||
panic();
|
||||
}
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void PoolBlock::serialize_sidechain_data()
|
||||
std::vector<uint8_t> PoolBlock::serialize_sidechain_data() const
|
||||
{
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
MutexLock lock(m_lock);
|
||||
|
||||
m_sideChainData.clear();
|
||||
m_sideChainData.reserve((m_uncles.size() + 4) * HASH_SIZE + 11);
|
||||
data.reserve((m_uncles.size() + 4) * HASH_SIZE + 20);
|
||||
|
||||
const hash& spend = m_minerWallet.spend_public_key();
|
||||
const hash& view = m_minerWallet.view_public_key();
|
||||
|
||||
m_sideChainData.insert(m_sideChainData.end(), spend.h, spend.h + HASH_SIZE);
|
||||
m_sideChainData.insert(m_sideChainData.end(), view.h, view.h + HASH_SIZE);
|
||||
m_sideChainData.insert(m_sideChainData.end(), m_txkeySec.h, m_txkeySec.h + HASH_SIZE);
|
||||
m_sideChainData.insert(m_sideChainData.end(), m_parent.h, m_parent.h + HASH_SIZE);
|
||||
data.insert(data.end(), spend.h, spend.h + HASH_SIZE);
|
||||
data.insert(data.end(), view.h, view.h + HASH_SIZE);
|
||||
data.insert(data.end(), m_txkeySec.h, m_txkeySec.h + HASH_SIZE);
|
||||
data.insert(data.end(), m_parent.h, m_parent.h + HASH_SIZE);
|
||||
|
||||
writeVarint(m_uncles.size(), m_sideChainData);
|
||||
writeVarint(m_uncles.size(), data);
|
||||
|
||||
for (const hash& id : m_uncles) {
|
||||
m_sideChainData.insert(m_sideChainData.end(), id.h, id.h + HASH_SIZE);
|
||||
data.insert(data.end(), id.h, id.h + HASH_SIZE);
|
||||
}
|
||||
|
||||
writeVarint(m_sidechainHeight, m_sideChainData);
|
||||
writeVarint(m_sidechainHeight, data);
|
||||
|
||||
writeVarint(m_difficulty.lo, m_sideChainData);
|
||||
writeVarint(m_difficulty.hi, m_sideChainData);
|
||||
writeVarint(m_difficulty.lo, data);
|
||||
writeVarint(m_difficulty.hi, data);
|
||||
|
||||
writeVarint(m_cumulativeDifficulty.lo, m_sideChainData);
|
||||
writeVarint(m_cumulativeDifficulty.hi, m_sideChainData);
|
||||
writeVarint(m_cumulativeDifficulty.lo, data);
|
||||
writeVarint(m_cumulativeDifficulty.hi, data);
|
||||
|
||||
#if POOL_BLOCK_DEBUG
|
||||
if (!m_sideChainDataDebug.empty() && (data != m_sideChainDataDebug)) {
|
||||
LOGERR(1, "serialize_sidechain_data() has a bug, fix it!");
|
||||
panic();
|
||||
}
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void PoolBlock::reset_offchain_data()
|
||||
@@ -274,16 +298,19 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const
|
||||
{
|
||||
MutexLock lock(m_lock);
|
||||
|
||||
if (!m_mainChainHeaderSize || !m_mainChainMinerTxSize || (m_mainChainData.size() < m_mainChainHeaderSize + m_mainChainMinerTxSize)) {
|
||||
size_t header_size, miner_tx_size;
|
||||
const std::vector<uint8_t> mainchain_data = serialize_mainchain_data_nolock(&header_size, &miner_tx_size, nullptr, nullptr);
|
||||
|
||||
if (!header_size || !miner_tx_size || (mainchain_data.size() < header_size + miner_tx_size)) {
|
||||
LOGERR(1, "tried to calculate PoW of uninitialized block");
|
||||
return false;
|
||||
}
|
||||
|
||||
blob_size = m_mainChainHeaderSize;
|
||||
memcpy(blob, m_mainChainData.data(), blob_size);
|
||||
blob_size = header_size;
|
||||
memcpy(blob, mainchain_data.data(), blob_size);
|
||||
|
||||
uint8_t* miner_tx = m_mainChainData.data() + m_mainChainHeaderSize;
|
||||
keccak(miner_tx, static_cast<int>(m_mainChainMinerTxSize) - 1, reinterpret_cast<uint8_t*>(hashes), HASH_SIZE);
|
||||
const uint8_t* miner_tx = mainchain_data.data() + header_size;
|
||||
keccak(miner_tx, static_cast<int>(miner_tx_size) - 1, reinterpret_cast<uint8_t*>(hashes), HASH_SIZE);
|
||||
|
||||
count = m_transactions.size();
|
||||
uint8_t* h = reinterpret_cast<uint8_t*>(m_transactions.data());
|
||||
@@ -329,11 +356,13 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const
|
||||
|
||||
uint64_t PoolBlock::get_payout(const Wallet& w) const
|
||||
{
|
||||
const uint8_t tx_type = get_tx_type();
|
||||
|
||||
for (size_t i = 0, n = m_outputs.size(); i < n; ++i) {
|
||||
const TxOutput& out = m_outputs[i];
|
||||
hash eph_public_key;
|
||||
|
||||
if (out.m_txType == TXOUT_TO_TAGGED_KEY) {
|
||||
if (tx_type == TXOUT_TO_TAGGED_KEY) {
|
||||
if (w.get_eph_public_key_with_view_tag(m_txkeySec, i, eph_public_key, out.m_viewTag) && (eph_public_key == out.m_ephPublicKey)) {
|
||||
return out.m_reward;
|
||||
}
|
||||
|
||||
+14
-16
@@ -63,13 +63,12 @@ struct PoolBlock
|
||||
|
||||
mutable uv_mutex_t m_lock;
|
||||
|
||||
// Monero block template
|
||||
std::vector<uint8_t> m_mainChainData;
|
||||
size_t m_mainChainHeaderSize;
|
||||
size_t m_mainChainMinerTxSize;
|
||||
int m_mainChainOutputsOffset;
|
||||
int m_mainChainOutputsBlobSize;
|
||||
#if POOL_BLOCK_DEBUG
|
||||
std::vector<uint8_t> m_mainChainDataDebug;
|
||||
std::vector<uint8_t> m_sideChainDataDebug;
|
||||
#endif
|
||||
|
||||
// Monero block template
|
||||
uint8_t m_majorVersion;
|
||||
uint8_t m_minorVersion;
|
||||
uint64_t m_timestamp;
|
||||
@@ -81,15 +80,16 @@ struct PoolBlock
|
||||
|
||||
struct TxOutput
|
||||
{
|
||||
FORCEINLINE TxOutput() : m_reward(0), m_ephPublicKey(), m_txType(0), m_viewTag(0) {}
|
||||
FORCEINLINE TxOutput(uint64_t r, const hash& k, uint8_t tx_type, uint8_t view_tag) : m_reward(r), m_ephPublicKey(k), m_txType(tx_type), m_viewTag(view_tag) {}
|
||||
FORCEINLINE TxOutput() : m_ephPublicKey(), m_reward(0), m_viewTag(0) {}
|
||||
FORCEINLINE TxOutput(uint64_t r, const hash& k, uint8_t view_tag) : m_ephPublicKey(k), m_reward(r), m_viewTag(view_tag) {}
|
||||
|
||||
uint64_t m_reward;
|
||||
hash m_ephPublicKey;
|
||||
uint8_t m_txType;
|
||||
uint8_t m_viewTag;
|
||||
uint64_t m_reward : 56;
|
||||
uint64_t m_viewTag : 8;
|
||||
};
|
||||
|
||||
static_assert(sizeof(TxOutput) == sizeof(hash) + sizeof(uint64_t), "TxOutput bit packing didn't work with this compiler, fix the code!");
|
||||
|
||||
std::vector<TxOutput> m_outputs;
|
||||
|
||||
hash m_txkeyPub;
|
||||
@@ -99,9 +99,6 @@ struct PoolBlock
|
||||
// All block transaction hashes including the miner transaction hash at index 0
|
||||
std::vector<hash> m_transactions;
|
||||
|
||||
// Side-chain data
|
||||
std::vector<uint8_t> m_sideChainData;
|
||||
|
||||
// Miner's wallet
|
||||
Wallet m_minerWallet{ nullptr };
|
||||
|
||||
@@ -134,8 +131,9 @@ struct PoolBlock
|
||||
|
||||
uint64_t m_localTimestamp;
|
||||
|
||||
void serialize_mainchain_data(uint32_t nonce, uint32_t extra_nonce, const hash& sidechain_hash);
|
||||
void serialize_sidechain_data();
|
||||
std::vector<uint8_t> serialize_mainchain_data(size_t* header_size = nullptr, size_t* miner_tx_size = nullptr, int* outputs_offset = nullptr, int* outputs_blob_size = nullptr) const;
|
||||
std::vector<uint8_t> serialize_mainchain_data_nolock(size_t* header_size, size_t* miner_tx_size, int* outputs_offset, int* outputs_blob_size) const;
|
||||
std::vector<uint8_t> serialize_sidechain_data() const;
|
||||
|
||||
int deserialize(const uint8_t* data, size_t size, const SideChain& sidechain, uv_loop_t* loop);
|
||||
void reset_offchain_data();
|
||||
|
||||
+35
-32
@@ -75,8 +75,6 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
const int nonce_offset = static_cast<int>(data - data_begin);
|
||||
READ_BUF(&m_nonce, NONCE_SIZE);
|
||||
|
||||
m_mainChainHeaderSize = data - data_begin;
|
||||
|
||||
EXPECT_BYTE(TX_VERSION);
|
||||
|
||||
uint64_t unlock_height;
|
||||
@@ -89,12 +87,13 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
if (unlock_height != m_txinGenHeight + MINER_REWARD_UNLOCK_TIME) return __LINE__;
|
||||
|
||||
std::vector<uint8_t> outputs_blob;
|
||||
m_mainChainOutputsOffset = static_cast<int>(data - data_begin);
|
||||
const int outputs_offset = static_cast<int>(data - data_begin);
|
||||
|
||||
uint64_t num_outputs;
|
||||
READ_VARINT(num_outputs);
|
||||
|
||||
uint64_t total_reward = 0;
|
||||
int outputs_blob_size;
|
||||
|
||||
if (num_outputs > 0) {
|
||||
// Outputs are in the buffer, just read them
|
||||
@@ -105,31 +104,32 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
if (num_outputs > std::numeric_limits<uint64_t>::max() / MIN_OUTPUT_SIZE) return __LINE__;
|
||||
if (static_cast<uint64_t>(data_end - data) < num_outputs * MIN_OUTPUT_SIZE) return __LINE__;
|
||||
|
||||
m_outputs.clear();
|
||||
m_outputs.reserve(num_outputs);
|
||||
m_outputs.resize(num_outputs);
|
||||
m_outputs.shrink_to_fit();
|
||||
|
||||
const uint8_t expected_tx_type = get_tx_type();
|
||||
|
||||
for (uint64_t i = 0; i < num_outputs; ++i) {
|
||||
TxOutput t;
|
||||
TxOutput& t = m_outputs[i];
|
||||
|
||||
READ_VARINT(t.m_reward);
|
||||
total_reward += t.m_reward;
|
||||
uint64_t reward;
|
||||
READ_VARINT(reward);
|
||||
t.m_reward = reward;
|
||||
total_reward += reward;
|
||||
|
||||
EXPECT_BYTE(expected_tx_type);
|
||||
t.m_txType = expected_tx_type;
|
||||
|
||||
READ_BUF(t.m_ephPublicKey.h, HASH_SIZE);
|
||||
|
||||
if (expected_tx_type == TXOUT_TO_TAGGED_KEY) {
|
||||
READ_BYTE(t.m_viewTag);
|
||||
uint8_t view_tag;
|
||||
READ_BYTE(view_tag);
|
||||
t.m_viewTag = view_tag;
|
||||
}
|
||||
|
||||
m_outputs.emplace_back(std::move(t));
|
||||
}
|
||||
|
||||
m_mainChainOutputsBlobSize = static_cast<int>(data - data_begin) - m_mainChainOutputsOffset;
|
||||
outputs_blob.assign(data_begin + m_mainChainOutputsOffset, data);
|
||||
outputs_blob_size = static_cast<int>(data - data_begin) - outputs_offset;
|
||||
outputs_blob.assign(data_begin + outputs_offset, data);
|
||||
}
|
||||
else {
|
||||
// Outputs are not in the buffer and must be calculated from sidechain data
|
||||
@@ -144,7 +144,7 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
m_mainChainOutputsBlobSize = static_cast<int>(tmp);
|
||||
outputs_blob_size = static_cast<int>(tmp);
|
||||
}
|
||||
|
||||
// Technically some p2pool node could keep stuffing block with transactions until reward is less than 0.6 XMR
|
||||
@@ -153,13 +153,12 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
const int outputs_actual_blob_size = static_cast<int>(data - data_begin) - m_mainChainOutputsOffset;
|
||||
|
||||
if (m_mainChainOutputsBlobSize < outputs_actual_blob_size) {
|
||||
const int outputs_actual_blob_size = static_cast<int>(data - data_begin) - outputs_offset;
|
||||
if (outputs_blob_size < outputs_actual_blob_size) {
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
const int outputs_blob_size_diff = m_mainChainOutputsBlobSize - outputs_actual_blob_size;
|
||||
const int outputs_blob_size_diff = outputs_blob_size - outputs_actual_blob_size;
|
||||
|
||||
uint64_t tx_extra_size;
|
||||
READ_VARINT(tx_extra_size);
|
||||
@@ -191,8 +190,6 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
|
||||
EXPECT_BYTE(0);
|
||||
|
||||
m_mainChainMinerTxSize = (data - data_begin) + outputs_blob_size_diff - m_mainChainHeaderSize;
|
||||
|
||||
uint64_t num_transactions;
|
||||
READ_VARINT(num_transactions);
|
||||
|
||||
@@ -208,12 +205,14 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
m_transactions.emplace_back(std::move(id));
|
||||
}
|
||||
|
||||
m_mainChainData.reserve((data - data_begin) + outputs_blob_size_diff);
|
||||
m_mainChainData.assign(data_begin, data_begin + m_mainChainOutputsOffset);
|
||||
m_mainChainData.insert(m_mainChainData.end(), m_mainChainOutputsBlobSize, 0);
|
||||
m_mainChainData.insert(m_mainChainData.end(), data_begin + m_mainChainOutputsOffset + outputs_actual_blob_size, data);
|
||||
#if POOL_BLOCK_DEBUG
|
||||
m_mainChainDataDebug.reserve((data - data_begin) + outputs_blob_size_diff);
|
||||
m_mainChainDataDebug.assign(data_begin, data_begin + outputs_offset);
|
||||
m_mainChainDataDebug.insert(m_mainChainDataDebug.end(), outputs_blob_size, 0);
|
||||
m_mainChainDataDebug.insert(m_mainChainDataDebug.end(), data_begin + outputs_offset + outputs_actual_blob_size, data);
|
||||
|
||||
const uint8_t* sidechain_data_begin = data;
|
||||
#endif
|
||||
|
||||
hash spend_pub_key;
|
||||
hash view_pub_key;
|
||||
@@ -276,16 +275,18 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
if (static_cast<int>(outputs_blob.size()) != m_mainChainOutputsBlobSize) {
|
||||
if (static_cast<int>(outputs_blob.size()) != outputs_blob_size) {
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
memcpy(m_mainChainData.data() + m_mainChainOutputsOffset, outputs_blob.data(), m_mainChainOutputsBlobSize);
|
||||
#if POOL_BLOCK_DEBUG
|
||||
memcpy(m_mainChainDataDebug.data() + outputs_offset, outputs_blob.data(), outputs_blob_size);
|
||||
#endif
|
||||
|
||||
hash check;
|
||||
const std::vector<uint8_t>& consensus_id = sidechain.consensus_id();
|
||||
keccak_custom(
|
||||
[this, nonce_offset, extra_nonce_offset, sidechain_hash_offset, data_begin, data_end, &consensus_id, &outputs_blob, outputs_blob_size_diff](int offset) -> uint8_t
|
||||
[nonce_offset, extra_nonce_offset, sidechain_hash_offset, data_begin, data_end, &consensus_id, &outputs_blob, outputs_blob_size_diff, outputs_offset, outputs_blob_size](int offset) -> uint8_t
|
||||
{
|
||||
uint32_t k = static_cast<uint32_t>(offset - nonce_offset);
|
||||
if (k < NONCE_SIZE) {
|
||||
@@ -304,11 +305,11 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
|
||||
const int data_size = static_cast<int>((data_end - data_begin) + outputs_blob_size_diff);
|
||||
if (offset < data_size) {
|
||||
if (offset < m_mainChainOutputsOffset) {
|
||||
if (offset < outputs_offset) {
|
||||
return data_begin[offset];
|
||||
}
|
||||
else if (offset < m_mainChainOutputsOffset + m_mainChainOutputsBlobSize) {
|
||||
const int tmp = offset - m_mainChainOutputsOffset;
|
||||
else if (offset < outputs_offset + outputs_blob_size) {
|
||||
const int tmp = offset - outputs_offset;
|
||||
return outputs_blob[tmp];
|
||||
}
|
||||
else {
|
||||
@@ -325,7 +326,9 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
m_sideChainData.assign(sidechain_data_begin, data_end);
|
||||
#if POOL_BLOCK_DEBUG
|
||||
m_sideChainDataDebug.assign(sidechain_data_begin, data_end);
|
||||
#endif
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
const char* msg = e.what();
|
||||
|
||||
+31
-13
@@ -32,6 +32,7 @@
|
||||
#include "stratum_server.h"
|
||||
#include "params.h"
|
||||
#include "json_parsers.h"
|
||||
#include "crypto.h"
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/istreamwrapper.h>
|
||||
#include <fstream>
|
||||
@@ -169,7 +170,11 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
|
||||
|
||||
// Use between 1 and 8 threads
|
||||
if (numThreads < 1) numThreads = 1;
|
||||
|
||||
// Don't limit thread count when debugging because debug builds are slow
|
||||
#ifndef P2POOL_DEBUGGING
|
||||
if (numThreads > 8) numThreads = 8;
|
||||
#endif
|
||||
|
||||
LOGINFO(4, "running " << numThreads << " pre-calculation workers");
|
||||
|
||||
@@ -527,7 +532,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
|
||||
MinerData miner_data = m_pool->miner_data();
|
||||
if ((block.m_prevId == miner_data.prev_id) && miner_data.difficulty.check_pow(pow_hash)) {
|
||||
LOGINFO(0, log::LightGreen() << "add_external_block: block " << block.m_sidechainId << " has enough PoW for Monero network, submitting it");
|
||||
m_pool->submit_block_async(block.m_mainChainData);
|
||||
m_pool->submit_block_async(block.serialize_mainchain_data());
|
||||
}
|
||||
else {
|
||||
difficulty_type diff;
|
||||
@@ -536,7 +541,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
|
||||
}
|
||||
else if (diff.check_pow(pow_hash)) {
|
||||
LOGINFO(0, log::LightGreen() << "add_external_block: block " << block.m_sidechainId << " has enough PoW for Monero height " << block.m_txinGenHeight << ", submitting it");
|
||||
m_pool->submit_block_async(block.m_mainChainData);
|
||||
m_pool->submit_block_async(block.serialize_mainchain_data());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,7 +579,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
|
||||
}
|
||||
|
||||
if (block_found) {
|
||||
m_pool->api_update_block_found(&data);
|
||||
m_pool->api_update_block_found(&data, &block);
|
||||
}
|
||||
|
||||
add_block(block);
|
||||
@@ -675,10 +680,10 @@ bool SideChain::get_block_blob(const hash& id, std::vector<uint8_t>& blob) const
|
||||
return false;
|
||||
}
|
||||
|
||||
blob.reserve(block->m_mainChainData.size() + block->m_sideChainData.size());
|
||||
blob = block->serialize_mainchain_data();
|
||||
const std::vector<uint8_t> sidechain_data = block->serialize_sidechain_data();
|
||||
blob.insert(blob.end(), sidechain_data.begin(), sidechain_data.end());
|
||||
|
||||
blob = block->m_mainChainData;
|
||||
blob.insert(blob.end(), block->m_sideChainData.begin(), block->m_sideChainData.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -696,13 +701,15 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
|
||||
blob.reserve(n * 39 + 64);
|
||||
writeVarint(n, blob);
|
||||
|
||||
const uint8_t tx_type = b->get_tx_type();
|
||||
|
||||
for (const PoolBlock::TxOutput& output : b->m_outputs) {
|
||||
writeVarint(output.m_reward, blob);
|
||||
blob.emplace_back(output.m_txType);
|
||||
blob.emplace_back(tx_type);
|
||||
blob.insert(blob.end(), output.m_ephPublicKey.h, output.m_ephPublicKey.h + HASH_SIZE);
|
||||
|
||||
if (output.m_txType == TXOUT_TO_TAGGED_KEY) {
|
||||
blob.emplace_back(output.m_viewTag);
|
||||
if (tx_type == TXOUT_TO_TAGGED_KEY) {
|
||||
blob.emplace_back(static_cast<uint8_t>(output.m_viewTag));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -808,9 +815,11 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
|
||||
blob.emplace_back(view_tag);
|
||||
}
|
||||
|
||||
block->m_outputs.emplace_back(tmpRewards[i], eph_public_key, tx_type, view_tag);
|
||||
block->m_outputs.emplace_back(tmpRewards[i], eph_public_key, view_tag);
|
||||
}
|
||||
|
||||
block->m_outputs.shrink_to_fit();
|
||||
|
||||
if (loop) {
|
||||
// this will cause all helper jobs to finish immediately
|
||||
counter = -1;
|
||||
@@ -911,12 +920,13 @@ void SideChain::print_status(bool obtain_sidechain_lock) const
|
||||
}
|
||||
|
||||
const Wallet& w = m_pool->params().m_wallet;
|
||||
const uint8_t tx_type = tip->get_tx_type();
|
||||
|
||||
hash eph_public_key;
|
||||
for (size_t i = 0, n = tip->m_outputs.size(); i < n; ++i) {
|
||||
const PoolBlock::TxOutput& out = tip->m_outputs[i];
|
||||
if (!your_reward) {
|
||||
if (out.m_txType == TXOUT_TO_TAGGED_KEY) {
|
||||
if (tx_type == TXOUT_TO_TAGGED_KEY) {
|
||||
if (w.get_eph_public_key_with_view_tag(tip->m_txkeySec, i, eph_public_key, out.m_viewTag) && (out.m_ephPublicKey == eph_public_key)) {
|
||||
your_reward = out.m_reward;
|
||||
}
|
||||
@@ -983,11 +993,12 @@ double SideChain::get_reward_share(const Wallet& w) const
|
||||
|
||||
const PoolBlock* tip = m_chainTip;
|
||||
if (tip) {
|
||||
const uint8_t tx_type = tip->get_tx_type();
|
||||
hash eph_public_key;
|
||||
for (size_t i = 0, n = tip->m_outputs.size(); i < n; ++i) {
|
||||
const PoolBlock::TxOutput& out = tip->m_outputs[i];
|
||||
if (!reward) {
|
||||
if (out.m_txType == TXOUT_TO_TAGGED_KEY) {
|
||||
if (tx_type == TXOUT_TO_TAGGED_KEY) {
|
||||
if (w.get_eph_public_key_with_view_tag(tip->m_txkeySec, i, eph_public_key, out.m_viewTag) && (out.m_ephPublicKey == eph_public_key)) {
|
||||
reward = out.m_reward;
|
||||
}
|
||||
@@ -1538,6 +1549,8 @@ void SideChain::verify(PoolBlock* block)
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t tx_type = block->get_tx_type();
|
||||
|
||||
for (size_t i = 0, n = rewards.size(); i < n; ++i) {
|
||||
const PoolBlock::TxOutput& out = block->m_outputs[i];
|
||||
|
||||
@@ -1561,7 +1574,7 @@ void SideChain::verify(PoolBlock* block)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((out.m_txType == TXOUT_TO_TAGGED_KEY) && (out.m_viewTag != view_tag)) {
|
||||
if ((tx_type == TXOUT_TO_TAGGED_KEY) && (out.m_viewTag != view_tag)) {
|
||||
LOGWARN(3, "block at height = " << block->m_sidechainHeight <<
|
||||
", id = " << block->m_sidechainId <<
|
||||
", mainchain height = " << block->m_txinGenHeight <<
|
||||
@@ -1622,6 +1635,8 @@ void SideChain::update_chain_tip(const PoolBlock* block)
|
||||
if (s) {
|
||||
s->reset_share_counters();
|
||||
}
|
||||
// Also clear cache because it has data from all old blocks now
|
||||
clear_crypto_cache();
|
||||
LOGINFO(0, log::LightCyan() << "SYNCHRONIZED");
|
||||
}
|
||||
}
|
||||
@@ -2125,6 +2140,9 @@ void SideChain::finish_precalc()
|
||||
LOGERR(1, "exception in finish_precalc(): " << e.what());
|
||||
}
|
||||
|
||||
// Also clear cache because it has data from all old blocks now
|
||||
clear_crypto_cache();
|
||||
|
||||
#ifdef DEV_TEST_SYNC
|
||||
if (m_pool) {
|
||||
LOGINFO(0, log::LightGreen() << "[DEV] Synchronization finished successfully, stopping P2Pool now");
|
||||
|
||||
+19
-11
@@ -45,7 +45,6 @@ StratumServer::StratumServer(p2pool* pool)
|
||||
: TCPServer(StratumClient::allocate)
|
||||
, m_pool(pool)
|
||||
, m_autoDiff(pool->params().m_autoDiff)
|
||||
, m_extraNonce(0)
|
||||
, m_rng(RandomDeviceSeed::instance)
|
||||
, m_cumulativeHashes(0)
|
||||
, m_cumulativeHashesAtLastShare(0)
|
||||
@@ -60,6 +59,8 @@ StratumServer::StratumServer(p2pool* pool)
|
||||
// Diffuse the initial state in case it has low quality
|
||||
m_rng.discard(10000);
|
||||
|
||||
m_extraNonce = static_cast<uint32_t>(m_rng());
|
||||
|
||||
m_hashrateData[0] = { seconds_since_epoch(), 0 };
|
||||
|
||||
uv_mutex_init_checked(&m_blobsQueueLock);
|
||||
@@ -84,8 +85,6 @@ StratumServer::StratumServer(p2pool* pool)
|
||||
|
||||
StratumServer::~StratumServer()
|
||||
{
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_blobsAsync), nullptr);
|
||||
|
||||
shutdown_tcp();
|
||||
|
||||
uv_mutex_destroy(&m_blobsQueueLock);
|
||||
@@ -106,9 +105,12 @@ void StratumServer::on_block(const BlockTemplate& block)
|
||||
LOGINFO(4, "no clients connected");
|
||||
return;
|
||||
}
|
||||
m_extraNonce.exchange(num_connections);
|
||||
|
||||
const uint32_t extra_nonce_start = static_cast<uint32_t>(get_random64());
|
||||
m_extraNonce.exchange(extra_nonce_start + num_connections);
|
||||
|
||||
BlobsData* blobs_data = new BlobsData{};
|
||||
blobs_data->m_extraNonceStart = extra_nonce_start;
|
||||
|
||||
difficulty_type difficulty;
|
||||
difficulty_type sidechain_difficulty;
|
||||
@@ -118,7 +120,7 @@ void StratumServer::on_block(const BlockTemplate& block)
|
||||
// Even if they do, they'll be added to the beginning of the list and will get their block template in on_login()
|
||||
// We'll iterate through the list backwards so when we get to the beginning and run out of extra_nonce values, it'll be only new clients left
|
||||
blobs_data->m_numClientsExpected = num_connections;
|
||||
blobs_data->m_blobSize = block.get_hashing_blobs(0, num_connections, blobs_data->m_blobs, blobs_data->m_height, difficulty, sidechain_difficulty, blobs_data->m_seedHash, nonce_offset, blobs_data->m_templateId);
|
||||
blobs_data->m_blobSize = block.get_hashing_blobs(extra_nonce_start, num_connections, blobs_data->m_blobs, blobs_data->m_height, difficulty, sidechain_difficulty, blobs_data->m_seedHash, nonce_offset, blobs_data->m_templateId);
|
||||
|
||||
// Integrity checks
|
||||
if (blobs_data->m_blobSize < 76) {
|
||||
@@ -664,9 +666,10 @@ void StratumServer::on_blobs_ready()
|
||||
|
||||
// Only send the latest blob
|
||||
BlobsData* data = blobs_queue.back();
|
||||
const uint32_t extra_nonce_start = data->m_extraNonceStart;
|
||||
|
||||
size_t numClientsProcessed = 0;
|
||||
uint32_t extra_nonce = 0;
|
||||
uint32_t num_sent = 0;
|
||||
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
{
|
||||
@@ -685,12 +688,12 @@ void StratumServer::on_blobs_ready()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (extra_nonce >= data->m_numClientsExpected) {
|
||||
if (num_sent >= data->m_numClientsExpected) {
|
||||
// We don't have any more extra_nonce values available
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t* hashing_blob = data->m_blobs.data() + extra_nonce * data->m_blobSize;
|
||||
uint8_t* hashing_blob = data->m_blobs.data() + num_sent * data->m_blobSize;
|
||||
|
||||
uint64_t target = data->m_target;
|
||||
if (client->m_customDiff.lo) {
|
||||
@@ -726,7 +729,7 @@ void StratumServer::on_blobs_ready()
|
||||
|
||||
StratumClient::SavedJob& saved_job = client->m_jobs[job_id % StratumClient::JOBS_SIZE];
|
||||
saved_job.job_id = job_id;
|
||||
saved_job.extra_nonce = extra_nonce;
|
||||
saved_job.extra_nonce = extra_nonce_start + num_sent;
|
||||
saved_job.template_id = data->m_templateId;
|
||||
saved_job.target = target;
|
||||
}
|
||||
@@ -752,7 +755,7 @@ void StratumServer::on_blobs_ready()
|
||||
});
|
||||
|
||||
if (result) {
|
||||
++extra_nonce;
|
||||
++num_sent;
|
||||
}
|
||||
else {
|
||||
client->close();
|
||||
@@ -765,7 +768,7 @@ void StratumServer::on_blobs_ready()
|
||||
}
|
||||
}
|
||||
|
||||
LOGINFO(3, "sent new job to " << extra_nonce << '/' << numClientsProcessed << " clients");
|
||||
LOGINFO(3, "sent new job to " << num_sent << '/' << numClientsProcessed << " clients");
|
||||
}
|
||||
|
||||
void StratumServer::update_hashrate_data(uint64_t hashes, uint64_t timestamp)
|
||||
@@ -935,6 +938,11 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
|
||||
}
|
||||
}
|
||||
|
||||
void StratumServer::on_shutdown()
|
||||
{
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_blobsAsync), nullptr);
|
||||
}
|
||||
|
||||
StratumServer::StratumClient::StratumClient()
|
||||
: m_rpcId(0)
|
||||
, m_perConnectionJobId(0)
|
||||
|
||||
@@ -103,6 +103,7 @@ private:
|
||||
|
||||
struct BlobsData
|
||||
{
|
||||
uint32_t m_extraNonceStart;
|
||||
std::vector<uint8_t> m_blobs;
|
||||
size_t m_blobSize;
|
||||
uint64_t m_target;
|
||||
@@ -179,6 +180,8 @@ private:
|
||||
|
||||
void update_hashrate_data(uint64_t hashes, uint64_t timestamp);
|
||||
void api_update_local_stats(uint64_t timestamp);
|
||||
|
||||
void on_shutdown() override;
|
||||
};
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
+8
-11
@@ -42,7 +42,7 @@ public:
|
||||
|
||||
uv_loop_t* get_loop() { return &m_loop; }
|
||||
|
||||
int listen_port() const { return m_listenPort; }
|
||||
virtual int listen_port() const { return m_listenPort; }
|
||||
|
||||
bool connect_to_peer(bool is_v6, const raw_ip& ip, int port);
|
||||
virtual void on_connect_failed(bool /*is_v6*/, const raw_ip& /*ip*/, int /*port*/) {}
|
||||
@@ -163,7 +163,6 @@ protected:
|
||||
int m_listenPort;
|
||||
|
||||
uv_loop_t m_loop;
|
||||
std::atomic<bool> m_loopStopped;
|
||||
|
||||
uv_mutex_t m_clientsListLock;
|
||||
std::vector<Client*> m_preallocatedClients;
|
||||
@@ -181,17 +180,15 @@ protected:
|
||||
uv_async_t m_dropConnectionsAsync;
|
||||
static void on_drop_connections(uv_async_t* async) { reinterpret_cast<TCPServer*>(async->data)->close_sockets(false); }
|
||||
|
||||
virtual void on_shutdown() = 0;
|
||||
|
||||
uv_async_t m_shutdownAsync;
|
||||
static void on_shutdown(uv_async_t* async)
|
||||
{
|
||||
TCPServer* server = reinterpret_cast<TCPServer*>(async->data);
|
||||
server->close_sockets(true);
|
||||
uv_prepare_t m_shutdownPrepare;
|
||||
uv_timer_t m_shutdownTimer;
|
||||
uint32_t m_shutdownCountdown;
|
||||
uint32_t m_numHandles;
|
||||
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&server->m_dropConnectionsAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&server->m_shutdownAsync), nullptr);
|
||||
|
||||
delete GetLoopUserData(&server->m_loop, false);
|
||||
}
|
||||
static void on_shutdown(uv_async_t* async);
|
||||
};
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
+65
-32
@@ -31,9 +31,12 @@ TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::TCPServer(allocate_client_callback all
|
||||
, m_finished(0)
|
||||
, m_listenPort(-1)
|
||||
, m_loop{}
|
||||
, m_loopStopped{false}
|
||||
, m_numConnections{ 0 }
|
||||
, m_numIncomingConnections{ 0 }
|
||||
, m_shutdownPrepare{}
|
||||
, m_shutdownTimer{}
|
||||
, m_shutdownCountdown(30)
|
||||
, m_numHandles(0)
|
||||
{
|
||||
int err = uv_loop_init(&m_loop);
|
||||
if (err) {
|
||||
@@ -433,35 +436,6 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::shutdown_tcp()
|
||||
}
|
||||
|
||||
uv_async_send(&m_shutdownAsync);
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
const auto start_time = steady_clock::now();
|
||||
int64_t counter = 0;
|
||||
uv_async_t asy;
|
||||
|
||||
constexpr uint32_t timeout_seconds = 30;
|
||||
|
||||
while (!m_loopStopped) {
|
||||
const int64_t elapsed_time = duration_cast<milliseconds>(steady_clock::now() - start_time).count();
|
||||
|
||||
if (elapsed_time >= (counter + 1) * 1000) {
|
||||
++counter;
|
||||
if (counter < timeout_seconds) {
|
||||
LOGINFO(1, "waiting for event loop to stop for " << (timeout_seconds - counter) << " more seconds...");
|
||||
}
|
||||
else {
|
||||
LOGWARN(1, "timed out while waiting for event loop to stop");
|
||||
uv_async_init(&m_loop, &asy, [](uv_async_t* h) { uv_close(reinterpret_cast<uv_handle_t*>(h), nullptr); });
|
||||
uv_stop(&m_loop);
|
||||
uv_async_send(&asy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(milliseconds(1));
|
||||
}
|
||||
|
||||
uv_thread_join(&m_loopThread);
|
||||
|
||||
uv_mutex_destroy(&m_clientsListLock);
|
||||
@@ -598,7 +572,6 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::loop(void* data)
|
||||
server->m_preallocatedClients.clear();
|
||||
|
||||
LOGINFO(1, "event loop stopped");
|
||||
server->m_loopStopped = true;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
@@ -729,7 +702,6 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server
|
||||
on_new_client(server, client);
|
||||
}
|
||||
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server, Client* client)
|
||||
{
|
||||
@@ -825,6 +797,67 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_shutdown(uv_async_t* async)
|
||||
{
|
||||
TCPServer* s = reinterpret_cast<TCPServer*>(async->data);
|
||||
s->on_shutdown();
|
||||
s->close_sockets(true);
|
||||
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&s->m_dropConnectionsAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&s->m_shutdownAsync), nullptr);
|
||||
|
||||
delete GetLoopUserData(&s->m_loop, false);
|
||||
|
||||
s->m_numHandles = 0;
|
||||
uv_walk(&s->m_loop, [](uv_handle_t*, void* n) { (*reinterpret_cast<size_t*>(n))++; }, &s->m_numHandles);
|
||||
|
||||
uv_prepare_init(&s->m_loop, &s->m_shutdownPrepare);
|
||||
s->m_shutdownPrepare.data = s;
|
||||
|
||||
uv_timer_init(&s->m_loop, &s->m_shutdownTimer);
|
||||
s->m_shutdownTimer.data = s;
|
||||
s->m_shutdownCountdown = 30;
|
||||
|
||||
uv_timer_start(&s->m_shutdownTimer,
|
||||
[](uv_timer_t* h)
|
||||
{
|
||||
TCPServer* s = reinterpret_cast<TCPServer*>(h->data);
|
||||
const uint32_t k = --s->m_shutdownCountdown;
|
||||
if (k > 0) {
|
||||
LOGINFO(1, "waiting for event loop to stop for " << k << " more seconds (" << s->m_numHandles << " handles left)...");
|
||||
}
|
||||
else {
|
||||
LOGINFO(1, "force stopping the event loop...");
|
||||
uv_timer_stop(&s->m_shutdownTimer);
|
||||
uv_prepare_stop(&s->m_shutdownPrepare);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&s->m_shutdownTimer), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&s->m_shutdownPrepare), nullptr);
|
||||
uv_stop(&s->m_loop);
|
||||
}
|
||||
}, 1000, 1000);
|
||||
|
||||
uv_prepare_start(&s->m_shutdownPrepare,
|
||||
[](uv_prepare_t* h)
|
||||
{
|
||||
TCPServer* s = reinterpret_cast<TCPServer*>(h->data);
|
||||
|
||||
s->m_numHandles = 0;
|
||||
uv_walk(&s->m_loop, [](uv_handle_t*, void* n) { (*reinterpret_cast<size_t*>(n))++; }, &s->m_numHandles);
|
||||
|
||||
if (s->m_numHandles > 2) {
|
||||
// Don't count m_shutdownTimer and m_shutdownPrepare
|
||||
s->m_numHandles -= 2;
|
||||
}
|
||||
else {
|
||||
uv_timer_stop(&s->m_shutdownTimer);
|
||||
uv_prepare_stop(&s->m_shutdownPrepare);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&s->m_shutdownTimer), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&s->m_shutdownPrepare), nullptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::Client()
|
||||
: m_owner(nullptr)
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ namespace p2pool {
|
||||
#define STR2(X) STR(X)
|
||||
#define STR(X) #X
|
||||
|
||||
const char* VERSION = "v2.4 (built"
|
||||
const char* VERSION = "v2.5 (built"
|
||||
#if defined(__clang__)
|
||||
" with clang/" __clang_version__
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
@@ -51,11 +51,16 @@ TEST(pool_block, deserialize)
|
||||
|
||||
ASSERT_EQ(b.deserialize(buf.data(), buf.size(), sidechain, nullptr), 0);
|
||||
|
||||
ASSERT_EQ(b.m_mainChainData.size(), 5607);
|
||||
ASSERT_EQ(b.m_mainChainHeaderSize, 43);
|
||||
ASSERT_EQ(b.m_mainChainMinerTxSize, 506);
|
||||
ASSERT_EQ(b.m_mainChainOutputsOffset, 54);
|
||||
ASSERT_EQ(b.m_mainChainOutputsBlobSize, 420);
|
||||
size_t header_size, miner_tx_size;
|
||||
int outputs_offset, outputs_blob_size;
|
||||
const std::vector<uint8_t> mainchain_data = b.serialize_mainchain_data(&header_size, &miner_tx_size, &outputs_offset, &outputs_blob_size);
|
||||
|
||||
ASSERT_EQ(mainchain_data.size(), 5607);
|
||||
ASSERT_EQ(header_size, 43);
|
||||
ASSERT_EQ(miner_tx_size, 506);
|
||||
ASSERT_EQ(outputs_offset, 54);
|
||||
ASSERT_EQ(outputs_blob_size, 420);
|
||||
|
||||
ASSERT_EQ(b.m_majorVersion, 14);
|
||||
ASSERT_EQ(b.m_minorVersion, 14);
|
||||
ASSERT_EQ(b.m_timestamp, 1630934403);
|
||||
@@ -65,7 +70,6 @@ TEST(pool_block, deserialize)
|
||||
ASSERT_EQ(b.m_extraNonceSize, 4);
|
||||
ASSERT_EQ(b.m_extraNonce, 28);
|
||||
ASSERT_EQ(b.m_transactions.size(), 159);
|
||||
ASSERT_EQ(b.m_sideChainData.size(), 146);
|
||||
ASSERT_EQ(b.m_uncles.size(), 0);
|
||||
ASSERT_EQ(b.m_sidechainHeight, 53450);
|
||||
ASSERT_EQ(b.m_difficulty.lo, 319296691);
|
||||
|
||||
Reference in New Issue
Block a user