Skip to content

Commit 69b8ea2

Browse files
Merge branch 'develop' of https://github.com/dashpay/dash into develop
2 parents 0e7bd53 + 7a549c4 commit 69b8ea2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1680
-1283
lines changed

.github/workflows/handle_potential_conflicts.py

Lines changed: 127 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,59 +19,166 @@
1919
"""
2020

2121
import sys
22+
import os
23+
import json
24+
import uuid
2225
import requests
2326

2427
# need to install via pip
25-
import hjson
28+
try:
29+
import hjson
30+
except ImportError:
31+
print("Error: hjson module not found. Please install it with: pip install hjson", file=sys.stderr)
32+
sys.exit(1)
2633

2734
def get_pr_json(pr_num):
28-
return requests.get(f'https://api.github.com/repos/dashpay/dash/pulls/{pr_num}').json()
35+
# Get repository from environment or default to dashpay/dash
36+
repo = os.environ.get('GITHUB_REPOSITORY', 'dashpay/dash')
37+
38+
try:
39+
response = requests.get(f'https://api.github.com/repos/{repo}/pulls/{pr_num}')
40+
response.raise_for_status()
41+
pr_data = response.json()
42+
43+
# Check if we got an error response
44+
if 'message' in pr_data and 'head' not in pr_data:
45+
print(f"Warning: GitHub API error for PR {pr_num}: {pr_data.get('message', 'Unknown error')}", file=sys.stderr)
46+
return None
47+
48+
return pr_data
49+
except requests.RequestException as e:
50+
print(f"Warning: Error fetching PR {pr_num}: {e}", file=sys.stderr)
51+
return None
52+
except json.JSONDecodeError as e:
53+
print(f"Warning: Error parsing JSON for PR {pr_num}: {e}", file=sys.stderr)
54+
return None
55+
56+
def set_github_output(name, value):
57+
"""Set GitHub Actions output"""
58+
if 'GITHUB_OUTPUT' not in os.environ:
59+
print(f"Warning: GITHUB_OUTPUT not set, skipping output: {name}={value}", file=sys.stderr)
60+
return
61+
62+
try:
63+
with open(os.environ['GITHUB_OUTPUT'], 'a', encoding='utf8') as f:
64+
# For multiline values, use the delimiter syntax
65+
if '\n' in str(value):
66+
delimiter = f"EOF_{uuid.uuid4()}"
67+
f.write(f"{name}<<{delimiter}\n{value}\n{delimiter}\n")
68+
else:
69+
f.write(f"{name}={value}\n")
70+
except IOError as e:
71+
print(f"Error writing to GITHUB_OUTPUT: {e}", file=sys.stderr)
2972

3073
def main():
3174
if len(sys.argv) != 2:
3275
print(f'Usage: {sys.argv[0]} <conflicts>', file=sys.stderr)
3376
sys.exit(1)
3477

35-
input = sys.argv[1]
36-
print(input)
37-
j_input = hjson.loads(input)
38-
print(j_input)
78+
conflict_input = sys.argv[1]
3979

80+
try:
81+
j_input = hjson.loads(conflict_input)
82+
except Exception as e:
83+
print(f"Error parsing input JSON: {e}", file=sys.stderr)
84+
sys.exit(1)
85+
86+
# Validate required fields
87+
if 'pull_number' not in j_input:
88+
print("Error: 'pull_number' field missing from input", file=sys.stderr)
89+
sys.exit(1)
90+
if 'conflictPrs' not in j_input:
91+
print("Error: 'conflictPrs' field missing from input", file=sys.stderr)
92+
sys.exit(1)
4093

4194
our_pr_num = j_input['pull_number']
42-
our_pr_label = get_pr_json(our_pr_num)['head']['label']
43-
conflictPrs = j_input['conflictPrs']
95+
our_pr_json = get_pr_json(our_pr_num)
96+
97+
if our_pr_json is None:
98+
print(f"Error: Failed to fetch PR {our_pr_num}", file=sys.stderr)
99+
sys.exit(1)
100+
101+
if 'head' not in our_pr_json or 'label' not in our_pr_json['head']:
102+
print(f"Error: Invalid PR data structure for PR {our_pr_num}", file=sys.stderr)
103+
sys.exit(1)
104+
105+
our_pr_label = our_pr_json['head']['label']
106+
conflict_prs = j_input['conflictPrs']
44107

45108
good = []
46109
bad = []
110+
conflict_details = []
111+
112+
for conflict in conflict_prs:
113+
if 'number' not in conflict:
114+
print("Warning: Skipping conflict entry without 'number' field", file=sys.stderr)
115+
continue
47116

48-
for conflict in conflictPrs:
49117
conflict_pr_num = conflict['number']
50-
print(conflict_pr_num)
51118

52119
conflict_pr_json = get_pr_json(conflict_pr_num)
120+
121+
if conflict_pr_json is None:
122+
print(f"Warning: Failed to fetch PR {conflict_pr_num}, skipping", file=sys.stderr)
123+
continue
124+
125+
if 'head' not in conflict_pr_json or 'label' not in conflict_pr_json['head']:
126+
print(f"Warning: Invalid PR data structure for PR {conflict_pr_num}, skipping", file=sys.stderr)
127+
continue
128+
53129
conflict_pr_label = conflict_pr_json['head']['label']
54-
print(conflict_pr_label)
55130

56-
if conflict_pr_json['mergeable_state'] == "dirty":
57-
print(f'{conflict_pr_num} needs rebase. Skipping conflict check')
131+
if conflict_pr_json.get('mergeable_state') == "dirty":
132+
print(f'PR #{conflict_pr_num} needs rebase. Skipping conflict check', file=sys.stderr)
58133
continue
59134

60-
if conflict_pr_json['draft']:
61-
print(f'{conflict_pr_num} is a draft. Skipping conflict check')
135+
if conflict_pr_json.get('draft', False):
136+
print(f'PR #{conflict_pr_num} is a draft. Skipping conflict check', file=sys.stderr)
137+
continue
138+
139+
# Get repository from environment
140+
repo = os.environ.get('GITHUB_REPOSITORY', 'dashpay/dash')
141+
merge_check_url = f'https://github.com/{repo}/branches/pre_mergeable/{our_pr_label}...{conflict_pr_label}'
142+
143+
try:
144+
pre_mergeable = requests.get(merge_check_url)
145+
pre_mergeable.raise_for_status()
146+
except requests.RequestException as e:
147+
print(f"Error checking mergeability for PR {conflict_pr_num}: {e}", file=sys.stderr)
62148
continue
63149

64-
pre_mergeable = requests.get(f'https://github.com/dashpay/dash/branches/pre_mergeable/{our_pr_label}...{conflict_pr_label}')
65150
if "These branches can be automatically merged." in pre_mergeable.text:
66151
good.append(conflict_pr_num)
67-
elif "Can’t automatically merge" in pre_mergeable.text:
152+
elif "Can't automatic" in pre_mergeable.text or "octicon octicon-x" in pre_mergeable.text:
153+
# Check for partial text or the X icon which indicates conflicts
68154
bad.append(conflict_pr_num)
155+
conflict_details.append({
156+
'number': conflict_pr_num,
157+
'title': conflict_pr_json.get('title', 'Unknown'),
158+
'url': conflict_pr_json.get('html_url', f'https://github.com/{repo}/pull/{conflict_pr_num}')
159+
})
160+
else:
161+
print(f"Warning: Unexpected response for PR {conflict_pr_num} mergeability check. URL: {pre_mergeable.url}", file=sys.stderr)
162+
163+
print(f"Not conflicting PRs: {good}", file=sys.stderr)
164+
print(f"Conflicting PRs: {bad}", file=sys.stderr)
165+
166+
# Set GitHub Actions outputs
167+
if 'GITHUB_OUTPUT' in os.environ:
168+
set_github_output('has_conflicts', 'true' if len(bad) > 0 else 'false')
169+
170+
# Format conflict details as markdown list
171+
if conflict_details:
172+
markdown_list = []
173+
for conflict in conflict_details:
174+
markdown_list.append(f"- #{conflict['number']} - [{conflict['title']}]({conflict['url']})")
175+
conflict_markdown = '\n'.join(markdown_list)
176+
set_github_output('conflict_details', conflict_markdown)
69177
else:
70-
raise Exception("not mergeable or unmergable!")
178+
set_github_output('conflict_details', '')
71179

72-
print("Not conflicting PRs: ", good)
180+
set_github_output('conflicting_prs', ','.join(map(str, bad)))
73181

74-
print("Conflicting PRs: ", bad)
75182
if len(bad) > 0:
76183
sys.exit(1)
77184

.github/workflows/predict-conflicts.yml

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,38 @@ jobs:
2323
runs-on: ubuntu-latest
2424
steps:
2525
- name: check for potential conflicts
26+
id: check_conflicts
2627
uses: PastaPastaPasta/[email protected]
2728
with:
2829
ghToken: "${{ secrets.GITHUB_TOKEN }}"
2930
- name: Checkout
30-
uses: actions/checkout@v3
31+
uses: actions/checkout@v4
3132
- name: validate potential conflicts
33+
id: validate_conflicts
3234
run: pip3 install hjson && .github/workflows/handle_potential_conflicts.py "$conflicts"
35+
continue-on-error: true
36+
- name: Post conflict comment
37+
if: steps.validate_conflicts.outputs.has_conflicts == 'true'
38+
uses: mshick/add-pr-comment@v2
39+
with:
40+
message-id: conflict-prediction
41+
message: |
42+
## ⚠️ Potential Merge Conflicts Detected
43+
44+
This PR has potential conflicts with the following open PRs:
45+
46+
${{ steps.validate_conflicts.outputs.conflict_details }}
47+
48+
Please coordinate with the authors of these PRs to avoid merge conflicts.
49+
- name: Remove conflict comment if no conflicts
50+
if: steps.validate_conflicts.outputs.has_conflicts == 'false'
51+
uses: mshick/add-pr-comment@v2
52+
with:
53+
message-id: conflict-prediction
54+
message: |
55+
## ✅ No Merge Conflicts Detected
56+
57+
This PR currently has no conflicts with other open PRs.
58+
- name: Fail if conflicts exist
59+
if: steps.validate_conflicts.outputs.has_conflicts == 'true'
60+
run: exit 1

src/Makefile.am

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ BITCOIN_CORE_H = \
230230
interfaces/ipc.h \
231231
interfaces/node.h \
232232
interfaces/wallet.h \
233+
instantsend/db.h \
234+
instantsend/instantsend.h \
235+
instantsend/lock.h \
236+
instantsend/signing.h \
233237
key.h \
234238
key_io.h \
235239
limitedmap.h \
@@ -243,7 +247,6 @@ BITCOIN_CORE_H = \
243247
llmq/dkgsessionhandler.h \
244248
llmq/dkgsessionmgr.h \
245249
llmq/ehf_signals.h \
246-
llmq/instantsend.h \
247250
llmq/options.h \
248251
llmq/params.h \
249252
llmq/quorums.h \
@@ -488,6 +491,10 @@ libbitcoin_node_a_SOURCES = \
488491
index/coinstatsindex.cpp \
489492
index/txindex.cpp \
490493
init.cpp \
494+
instantsend/db.cpp \
495+
instantsend/instantsend.cpp \
496+
instantsend/lock.cpp \
497+
instantsend/signing.cpp \
491498
llmq/blockprocessor.cpp \
492499
llmq/chainlocks.cpp \
493500
llmq/clsig.cpp \
@@ -498,7 +505,6 @@ libbitcoin_node_a_SOURCES = \
498505
llmq/dkgsessionhandler.cpp \
499506
llmq/dkgsessionmgr.cpp \
500507
llmq/ehf_signals.cpp \
501-
llmq/instantsend.cpp \
502508
llmq/options.cpp \
503509
llmq/quorums.cpp \
504510
llmq/signing.cpp \

src/bench/rpc_blockchain.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
#include <bench/data.h>
77

88
#include <consensus/validation.h>
9+
#include <instantsend/instantsend.h>
910
#include <llmq/chainlocks.h>
1011
#include <llmq/context.h>
11-
#include <llmq/instantsend.h>
1212
#include <rpc/blockchain.h>
1313
#include <streams.h>
1414
#include <test/util/setup_common.h>

src/coinjoin/coinjoin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
#include <chainparams.h>
1010
#include <consensus/validation.h>
1111
#include <governance/common.h>
12+
#include <instantsend/instantsend.h>
1213
#include <llmq/chainlocks.h>
13-
#include <llmq/instantsend.h>
1414
#include <masternode/node.h>
1515
#include <masternode/sync.h>
1616
#include <messagesigner.h>

src/dsnotificationinterface.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@
1616

1717
#include <evo/deterministicmns.h>
1818
#include <evo/mnauth.h>
19-
19+
#include <instantsend/instantsend.h>
2020
#include <llmq/chainlocks.h>
2121
#include <llmq/context.h>
2222
#include <llmq/dkgsessionmgr.h>
2323
#include <llmq/ehf_signals.h>
24-
#include <llmq/instantsend.h>
2524
#include <llmq/quorums.h>
2625

2726
CDSNotificationInterface::CDSNotificationInterface(CConnman& connman,

src/evo/chainhelper.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66

77
#include <consensus/params.h>
88
#include <evo/specialtxman.h>
9+
#include <instantsend/instantsend.h>
10+
#include <instantsend/lock.h>
911
#include <llmq/chainlocks.h>
10-
#include <llmq/instantsend.h>
1112
#include <masternode/payments.h>
1213

1314
CChainstateHelper::CChainstateHelper(CCreditPoolManager& cpoolman, CDeterministicMNManager& dmnman,

src/init.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@
8787
#include <evo/mnhftx.h>
8888
#include <flat-database.h>
8989
#include <governance/governance.h>
90+
#include <instantsend/instantsend.h>
9091
#include <llmq/context.h>
9192
#include <llmq/dkgsessionmgr.h>
9293
#include <llmq/options.h>
9394
#include <llmq/signing.h>
94-
#include <llmq/instantsend.h>
9595
#include <masternode/meta.h>
9696
#include <masternode/node.h>
9797
#include <masternode/sync.h>

0 commit comments

Comments
 (0)