Skip to content
This repository has been archived by the owner on Oct 20, 2023. It is now read-only.

Ltc fix #1563

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from
Open

Ltc fix #1563

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/litecoin_dash_pool.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@
"payoutSchemeConfig": {
"factor": 2.0
}
}
},
"addressType": "litecoin"
},
{
"id": "dash1",
Expand Down
3 changes: 2 additions & 1 deletion examples/litecoin_pool.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
"payoutSchemeConfig": {
"factor": 2.0
}
}
},
"addressType": "litecoin"
}]
}
5 changes: 5 additions & 0 deletions src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ public enum BitcoinAddressType
/// Bitcoin Cash
/// </summary>
BCash,

/// <summary>
/// Litecoin
/// </summary>
Litecoin
}

public enum BitcoinTransactionCategory
Expand Down
26 changes: 19 additions & 7 deletions src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,10 @@ protected virtual Transaction CreateOutputTransaction()
if(coin.HasMasterNodes)
rewardToPool = CreateMasternodeOutputs(tx, rewardToPool);

if (coin.HasFounderFee)
if(coin.HasFounderFee)
rewardToPool = CreateFounderOutputs(tx, rewardToPool);

if (coin.HasMinerFund)
if(coin.HasMinerFund)
rewardToPool = CreateMinerFundOutputs(tx, rewardToPool);

// Remaining amount goes to pool
Expand Down Expand Up @@ -410,6 +410,18 @@ protected virtual byte[] SerializeBlock(byte[] header, byte[] coinbase)
if(isPoS)
bs.ReadWrite((byte) 0);

// if pool supports MWEB, we have to append the MWEB data to the block
// https://github.com/litecoin-project/litecoin/blob/0.21/doc/mweb/mining-changes.md
if(coin.HasMWEB)
{
var separator = new byte[] { 0x01 };
var mweb = BlockTemplate.Extra.SafeExtensionDataAs<MwebBlockTemplateExtra>();
var mwebRaw = mweb.Mweb.HexToByteArray();

bs.ReadWrite(ref separator);
bs.ReadWrite(ref mwebRaw);
}

return stream.ToArray();
}
}
Expand Down Expand Up @@ -492,10 +504,10 @@ protected virtual Money CreateMasternodeOutputs(Transaction tx, Money reward)

protected virtual Money CreateFounderOutputs(Transaction tx, Money reward)
{
if (founderParameters.Founder != null)
if(founderParameters.Founder != null)
{
Founder[] founders;
if (founderParameters.Founder.Type == JTokenType.Array)
if(founderParameters.Founder.Type == JTokenType.Array)
founders = founderParameters.Founder.ToObject<Founder[]>();
else
founders = new[] { founderParameters.Founder.ToObject<Founder>() };
Expand Down Expand Up @@ -529,7 +541,7 @@ protected virtual Money CreateMinerFundOutputs(Transaction tx, Money reward)
{
var payeeReward = minerFundParameters.MinimumValue;

if (!string.IsNullOrEmpty(minerFundParameters.Addresses?.FirstOrDefault()))
if(!string.IsNullOrEmpty(minerFundParameters.Addresses?.FirstOrDefault()))
{
var payeeAddress = BitcoinUtils.AddressToDestination(minerFundParameters.Addresses[0], network);
tx.Outputs.Add(payeeReward, payeeAddress);
Expand Down Expand Up @@ -612,10 +624,10 @@ public void Init(BlockTemplate blockTemplate, string jobId,
if(coin.HasPayee)
payeeParameters = BlockTemplate.Extra.SafeExtensionDataAs<PayeeBlockTemplateExtra>();

if (coin.HasFounderFee)
if(coin.HasFounderFee)
founderParameters = BlockTemplate.Extra.SafeExtensionDataAs<FounderBlockTemplateExtra>();

if (coin.HasMinerFund)
if(coin.HasMinerFund)
minerFundParameters = BlockTemplate.Extra.SafeExtensionDataAs<MinerFundTemplateExtra>("coinbasetxn", "minerfund");

this.coinbaseHasher = coinbaseHasher;
Expand Down
49 changes: 47 additions & 2 deletions src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using Org.BouncyCastle.Crypto.Parameters;

namespace Miningcore.Blockchain.Bitcoin;

Expand All @@ -33,17 +34,61 @@ protected override object[] GetBlockTemplateParams()
{
var result = base.GetBlockTemplateParams();

if(coin.HasMWEB)
{
result = new object[]
{
new
{
rules = new[] {"segwit", "mweb"},
}
};
}

if(coin.BlockTemplateRpcExtraParams != null)
{
if(coin.BlockTemplateRpcExtraParams.Type == JTokenType.Array)
result = result.Concat(coin.BlockTemplateRpcExtraParams.ToObject<object[]>() ?? Array.Empty<object>()).ToArray();
else
result = result.Concat(new []{ coin.BlockTemplateRpcExtraParams.ToObject<object>()}).ToArray();
result = result.Concat(new[] { coin.BlockTemplateRpcExtraParams.ToObject<object>() }).ToArray();
}

return result;
}

protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct)
{
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5));

var syncPendingNotificationShown = false;

do
{
var response = await rpc.ExecuteAsync<BlockTemplate>(logger,
BitcoinCommands.GetBlockTemplate, ct, GetBlockTemplateParams());

var isSynched = response.Error == null;

if(isSynched)
{
logger.Info(() => "All daemons synched with blockchain");
break;
}
else
{
logger.Debug(() => $"Daemon reports error: {response.Error?.Message}");
}

if(!syncPendingNotificationShown)
{
logger.Info(() => "Daemon is still syncing with network. Manager will be started once synced.");
syncPendingNotificationShown = true;
}

await ShowDaemonSyncProgressAsync(ct);
} while(await timer.WaitForNextTickAsync(ct));
}

protected async Task<RpcResponse<BlockTemplate>> GetBlockTemplateAsync(CancellationToken ct)
{
var result = await rpc.ExecuteAsync<BlockTemplate>(logger,
Expand Down Expand Up @@ -71,7 +116,7 @@ protected override void PostChainIdentifyConfigure()
if(poolConfig.EnableInternalStratum == true && coin.HeaderHasherValue is IHashAlgorithmInit hashInit)
{
if(!hashInit.DigestInit(poolConfig))
logger.Error(()=> $"{hashInit.GetType().Name} initialization failed");
logger.Error(() => $"{hashInit.GetType().Name} initialization failed");
}
}

Expand Down
26 changes: 17 additions & 9 deletions src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ protected async Task<SubmitResult> SubmitBlockAsync(Share share, string blockHex
? new RpcRequest(BitcoinCommands.SubmitBlock, new[] { blockHex })
: new RpcRequest(BitcoinCommands.GetBlockTemplate, new { mode = "submit", data = blockHex });

var batch = new []
var batch = new[]
{
submitBlockRequest,
new RpcRequest(BitcoinCommands.GetBlock, new[] { share.BlockHash })
Expand Down Expand Up @@ -381,7 +381,12 @@ protected override async Task<bool> AreDaemonsHealthyAsync(CancellationToken ct)

var response = await rpc.ExecuteAsync<BlockchainInfo>(logger, BitcoinCommands.GetBlockchainInfo, ct);

return response.Error == null;
if(response.Error != null)
{
logger.Error(() => $"Daemon reports: {response.Error.Message}");
return false;
}
return true;
}

protected override async Task<bool> AreDaemonsConnectedAsync(CancellationToken ct)
Expand Down Expand Up @@ -466,17 +471,17 @@ protected override async Task PostStartInitAsync(CancellationToken ct)
PostChainIdentifyConfigure();

// ensure pool owns wallet
if(validateAddressResponse is not {IsValid: true})
if(validateAddressResponse is not { IsValid: true })
throw new PoolStartupException($"Daemon reports pool-address '{poolConfig.Address}' as invalid", poolConfig.Id);

isPoS = poolConfig.Template is BitcoinTemplate {IsPseudoPoS: true} ||
isPoS = poolConfig.Template is BitcoinTemplate { IsPseudoPoS: true } ||
(difficultyResponse.Values().Any(x => x.Path == "proof-of-stake" && !difficultyResponse.Values().Any(x => x.Path == "proof-of-work")));

// Create pool address script from response
if(!isPoS)
{
if(extraPoolConfig != null && extraPoolConfig.AddressType != BitcoinAddressType.Legacy)
logger.Info(()=> $"Interpreting pool address {poolConfig.Address} as type {extraPoolConfig?.AddressType.ToString()}");
logger.Info(() => $"Interpreting pool address {poolConfig.Address} as type {extraPoolConfig?.AddressType.ToString()}");

poolAddressDestination = AddressToDestination(poolConfig.Address, extraPoolConfig?.AddressType);
}
Expand All @@ -488,8 +493,8 @@ protected override async Task PostStartInitAsync(CancellationToken ct)
if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true)
{
// ensure pool owns wallet
if(validateAddressResponse is {IsMine: false} && addressInfoResponse is {IsMine: false})
logger.Warn(()=> $"Daemon does not own pool-address '{poolConfig.Address}'");
if(validateAddressResponse is { IsMine: false } && addressInfoResponse is { IsMine: false })
logger.Warn(() => $"Daemon does not own pool-address '{poolConfig.Address}'");
}

// update stats
Expand All @@ -512,7 +517,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct)
// Periodically update network stats
Observable.Interval(TimeSpan.FromMinutes(10))
.Select(_ => Observable.FromAsync(() =>
Guard(()=> !hasLegacyDaemon ? UpdateNetworkStatsAsync(ct) : UpdateNetworkStatsLegacyAsync(ct),
Guard(() => !hasLegacyDaemon ? UpdateNetworkStatsAsync(ct) : UpdateNetworkStatsLegacyAsync(ct),
ex => logger.Error(ex))))
.Concat()
.Subscribe();
Expand All @@ -534,6 +539,9 @@ protected virtual IDestination AddressToDestination(string address, BitcoinAddre
case BitcoinAddressType.BCash:
return BitcoinUtils.BCashAddressToDestination(poolConfig.Address, network);

case BitcoinAddressType.Litecoin:
return BitcoinUtils.LitecoinAddressToDestination(poolConfig.Address, network);

default:
return BitcoinUtils.AddressToDestination(poolConfig.Address, network);
}
Expand Down Expand Up @@ -573,7 +581,7 @@ public virtual async Task<bool> ValidateAddressAsync(string address, Cancellatio

var result = await rpc.ExecuteAsync<ValidateAddressResponse>(logger, BitcoinCommands.ValidateAddress, ct, new[] { address });

return result.Response is {IsValid: true};
return result.Response is { IsValid: true };
}

#endregion // API-Surface
Expand Down
13 changes: 13 additions & 0 deletions src/Miningcore/Blockchain/Bitcoin/BitcoinUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,17 @@ public static IDestination BCashAddressToDestination(string address, Network exp
var trashAddress = bcash.Parse<NBitcoin.Altcoins.BCash.BTrashPubKeyAddress>(address);
return trashAddress.ScriptPubKey.GetDestinationAddress(bcash);
}

public static IDestination LitecoinAddressToDestination(string address, Network expectedNetwork)
{
var litecoin = NBitcoin.Altcoins.Litecoin.Instance.GetNetwork(expectedNetwork.ChainName);
var encoder = litecoin.GetBech32Encoder(Bech32Type.WITNESS_PUBKEY_ADDRESS, true);

var decoded = encoder.Decode(address, out var witVersion);
var result = new WitKeyId(decoded);

Debug.Assert(result.GetAddress(litecoin).ToString() == address);
return result;
}
}

6 changes: 6 additions & 0 deletions src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Mweb.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Miningcore.Blockchain.Bitcoin.DaemonResponses;

public class MwebBlockTemplateExtra
{
public string Mweb { get; set; }
}
11 changes: 7 additions & 4 deletions src/Miningcore/Configuration/ClusterConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public enum CoinFamily

[EnumMember(Value = "conceal")]
Conceal,

[EnumMember(Value = "cryptonote")]
Cryptonote,

Expand Down Expand Up @@ -214,6 +214,9 @@ public class BitcoinNetworkParams
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public JToken BlockTemplateRpcExtraParams { get; set; }

[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public bool HasMWEB { get; set; }

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public Dictionary<string, BitcoinNetworkParams> Networks { get; set; }

Expand Down Expand Up @@ -438,13 +441,13 @@ public partial class ConcealCoinTemplate : CoinTemplate
/// </summary>
[JsonProperty(Order = -4, DefaultValueHandling = DefaultValueHandling.Include)]
public int HashVariant { get; set; }

/// <summary>
/// Conceal network hashrate = `Difficulty / DifficultyTarget`
/// See: parameter -> DIFFICULTY_TARGET in src/CryptoNoteConfig.h
/// </summary>
public ulong DifficultyTarget { get; set; }

/// <summary>
/// Smallest unit for Blockreward formatting
/// </summary>
Expand Down Expand Up @@ -830,7 +833,7 @@ public partial class ClusterPaymentProcessingConfig
/// <summary>
/// Indentifier used in coinbase transactions to identify the pool
/// </summary>
public string CoinbaseString { get; set; }
public string CoinbaseString { get; set; }
}

public partial class PersistenceConfig
Expand Down
Loading