Skip to content

Commit

Permalink
introduce tracked source context
Browse files Browse the repository at this point in the history
  • Loading branch information
Kukks committed Nov 16, 2023
1 parent a36c7aa commit 75668ec
Show file tree
Hide file tree
Showing 10 changed files with 392 additions and 384 deletions.
2 changes: 2 additions & 0 deletions NBXplorer.Tests/UnitTest1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4476,7 +4476,9 @@ private async Task Eventually(Func<Task> tsk)

[Theory]
[InlineData(Backend.Postgres)]
#if SUPPORT_DBTRIE
[InlineData(Backend.DBTrie)]
#endif
public async Task CanAssociateIndependentScripts(Backend backend)
{
using var tester = ServerTester.Create(backend);
Expand Down
12 changes: 12 additions & 0 deletions NBXplorer/Controllers/CommonRoutes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace NBXplorer.Controllers;

public static class CommonRoutes
{
public const string BaseCryptoEndpoint = "cryptos/{cryptoCode}";
public const string BaseDerivationEndpoint = $"{BaseCryptoEndpoint}/derivations";
public const string DerivationEndpoint = $"{BaseCryptoEndpoint}/derivations/{{derivationScheme}}";
public const string AddressEndpoint = $"{BaseCryptoEndpoint}/addresses/{{address}}";
public const string WalletEndpoint = $"{BaseCryptoEndpoint}/wallets/{{walletId}}";
public const string TrackedSourceEndpoint = $"{BaseCryptoEndpoint}/tracked-sources/{{trackedSource}}";
public const string TransactionsPath = "transactions/{txId?}";
}
12 changes: 1 addition & 11 deletions NBXplorer/Controllers/ControllerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,7 @@ public ControllerBase(
public IRepositoryProvider RepositoryProvider { get; }
public IIndexers Indexers { get; }

internal static TrackedSource GetTrackedSource(DerivationStrategyBase derivationScheme, BitcoinAddress address, string walletId)
{
TrackedSource trackedSource = null;
if (address != null)
trackedSource = new AddressTrackedSource(address);
if (derivationScheme != null)
trackedSource = new DerivationSchemeTrackedSource(derivationScheme);
if (walletId != null)
trackedSource = new WalletTrackedSource(walletId);
return trackedSource;
}

internal NBXplorerNetwork GetNetwork(string cryptoCode, bool checkRPC)
{
if (cryptoCode == null)
Expand Down
47 changes: 21 additions & 26 deletions NBXplorer/Controllers/MainController.PSBT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,26 @@ namespace NBXplorer.Controllers
public partial class MainController
{
[HttpPost]
[Route("cryptos/{network}/derivations/{strategy}/psbt/create")]
[Route($"{CommonRoutes.DerivationEndpoint}/psbt/create")]
[TrackedSourceContext.TrackedSourceContextRequirement(allowedTrackedSourceTypes:typeof(DerivationSchemeTrackedSource))]
public async Task<IActionResult> CreatePSBT(
[ModelBinder(BinderType = typeof(NetworkModelBinder))]
NBXplorerNetwork network,
[ModelBinder(BinderType = typeof(DerivationStrategyModelBinder))]
DerivationStrategyBase strategy,
TrackedSourceContext trackedSourceContext,
[FromBody]
JObject body,
[FromServices]
IUTXOService utxoService)
{
if (body == null)
throw new ArgumentNullException(nameof(body));
CreatePSBTRequest request = ParseJObject<CreatePSBTRequest>(body, network);
if (strategy == null)
throw new ArgumentNullException(nameof(strategy));

var repo = RepositoryProvider.GetRepository(network);
var txBuilder = request.Seed is int s ? network.NBitcoinNetwork.CreateTransactionBuilder(s)
: network.NBitcoinNetwork.CreateTransactionBuilder();
CreatePSBTRequest request = ParseJObject<CreatePSBTRequest>(body, trackedSourceContext.Network);

var repo = RepositoryProvider.GetRepository(trackedSourceContext.Network);
var txBuilder = request.Seed is int s ? trackedSourceContext.Network.NBitcoinNetwork.CreateTransactionBuilder(s)
: trackedSourceContext.Network.NBitcoinNetwork.CreateTransactionBuilder();
var strategy = ((DerivationSchemeTrackedSource) trackedSourceContext.TrackedSource).DerivationStrategy;
CreatePSBTSuggestions suggestions = null;
if (!(request.DisableFingerprintRandomization is true) &&
fingerprintService.GetDistribution(network) is FingerprintDistribution distribution)
fingerprintService.GetDistribution(trackedSourceContext.Network) is FingerprintDistribution distribution)
{
suggestions ??= new CreatePSBTSuggestions();
var known = new List<(Fingerprint feature, bool value)>();
Expand Down Expand Up @@ -97,8 +93,7 @@ public async Task<IActionResult> CreatePSBT(
suggestions.ShouldEnforceLowR = fingerprint.HasFlag(Fingerprint.LowR);
}

var indexer = Indexers.GetIndexer(network);
if (indexer.NetworkInfo?.GetRelayFee() is FeeRate feeRate)
if (trackedSourceContext.Indexer.NetworkInfo?.GetRelayFee() is FeeRate feeRate)
{
txBuilder.StandardTransactionPolicy.MinRelayTxFee = feeRate;
}
Expand Down Expand Up @@ -135,7 +130,7 @@ public async Task<IActionResult> CreatePSBT(
// nLockTime that preclude a fix later.
else if (!(request.DiscourageFeeSniping is false))
{
if (indexer.State is BitcoinDWaiterState.Ready)
if (trackedSourceContext.Indexer.State is BitcoinDWaiterState.Ready)
{
int blockHeight = (await repo.GetTip()).Height;
// Secondly occasionally randomly pick a nLockTime even further back, so
Expand All @@ -153,7 +148,7 @@ public async Task<IActionResult> CreatePSBT(
txBuilder.SetLockTime(new LockTime(0));
}
}
var utxoChanges = (await utxoService.GetUTXOs(network.CryptoCode, strategy)).As<UTXOChanges>();
var utxoChanges = (await utxoService.GetUTXOs(trackedSourceContext)).As<UTXOChanges>();
var utxos = utxoChanges.GetUnspentUTXOs(request.MinConfirmations);
var availableCoinsByOutpoint = utxos.ToDictionary(o => o.Outpoint);
if (request.IncludeOnlyOutpoints != null)
Expand Down Expand Up @@ -194,10 +189,10 @@ public async Task<IActionResult> CreatePSBT(
// We remove unconf utxos with too many ancestors, as it will result in a transaction
// that can't be broadcasted.
// We do only for BTC, as this isn't a shitcoin issue.
if (network.CryptoCode == "BTC" && unconfUtxos.Count > 0 && request.MinConfirmations == 0)
if (trackedSourceContext.Network.CryptoCode == "BTC" && unconfUtxos.Count > 0 && request.MinConfirmations == 0)
{
HashSet<uint256> requestedTxs = new HashSet<uint256>();
var rpc = RPCClients.Get(network);
var rpc = trackedSourceContext.RpcClient;
rpc = rpc.PrepareBatch();
var mempoolEntries =
unconfUtxos
Expand Down Expand Up @@ -270,7 +265,7 @@ public async Task<IActionResult> CreatePSBT(
bool hasChange = false;
if (request.ExplicitChangeAddress == null)
{
var keyInfo = (await GetUnusedAddress(network.CryptoCode, strategy, DerivationFeature.Change, autoTrack: true)).As<KeyPathInformation>();
var keyInfo = (await GetUnusedAddress(trackedSourceContext, DerivationFeature.Change, autoTrack: true)).As<KeyPathInformation>();
change = (keyInfo.ScriptPubKey, keyInfo.KeyPath);
}
else
Expand All @@ -296,7 +291,7 @@ public async Task<IActionResult> CreatePSBT(
{
try
{
var rate = await GetFeeRate(blockTarget, network.CryptoCode);
var rate = await GetFeeRate(blockTarget, trackedSourceContext.Network.CryptoCode);
txBuilder.SendEstimatedFees(rate.FeeRate);
}
catch (NBXplorerException e) when (e.Error.Code == "fee-estimation-unavailable" && request.FeePreference?.FallbackFeeRate is FeeRate fallbackFeeRate)
Expand All @@ -312,7 +307,7 @@ public async Task<IActionResult> CreatePSBT(
{
try
{
var rate = await GetFeeRate(1, network.CryptoCode);
var rate = await GetFeeRate(1, trackedSourceContext.Network.CryptoCode);
txBuilder.SendEstimatedFees(rate.FeeRate);
}
catch (NBXplorerException e) when (e.Error.Code == "fee-estimation-unavailable" && request.FeePreference?.FallbackFeeRate is FeeRate fallbackFeeRate)
Expand Down Expand Up @@ -351,7 +346,7 @@ public async Task<IActionResult> CreatePSBT(
// We made sure we can build the PSBT, so now we can reserve the change address if we need to
if (hasChange && request.ExplicitChangeAddress == null && request.ReserveChangeAddress)
{
var derivation = (await GetUnusedAddress(network.CryptoCode, strategy, DerivationFeature.Change, reserve: true, autoTrack: true)).As<KeyPathInformation>();
var derivation = (await GetUnusedAddress(trackedSourceContext, DerivationFeature.Change, reserve: true, autoTrack: true)).As<KeyPathInformation>();
// In most of the time, this is the same as previously, so no need to rebuild PSBT
if (derivation.ScriptPubKey != change.ScriptPubKey)
{
Expand All @@ -375,14 +370,14 @@ public async Task<IActionResult> CreatePSBT(
AlwaysIncludeNonWitnessUTXO = request.AlwaysIncludeNonWitnessUTXO,
IncludeGlobalXPub = request.IncludeGlobalXPub
};
await UpdatePSBTCore(update, network);
await UpdatePSBTCore(update, trackedSourceContext.Network);
var resp = new CreatePSBTResponse()
{
PSBT = update.PSBT,
ChangeAddress = hasChange ? change.ScriptPubKey.GetDestinationAddress(network.NBitcoinNetwork) : null,
ChangeAddress = hasChange ? change.ScriptPubKey.GetDestinationAddress(trackedSourceContext.Network.NBitcoinNetwork) : null,
Suggestions = suggestions
};
return Json(resp, network.JsonSerializerSettings);
return Json(resp, trackedSourceContext.Network.JsonSerializerSettings);
}

[HttpPost]
Expand Down
Loading

0 comments on commit 75668ec

Please sign in to comment.