Skip to content

Commit fad61c2

Browse files
authored
Merge pull request #688 from YoungHypo/issue-commit-backend
Enhance backend support for chaincode commit
2 parents 36a541c + e8e01ed commit fad61c2

File tree

3 files changed

+180
-104
lines changed

3 files changed

+180
-104
lines changed

src/api-engine/api/lib/peer/chaincode.py

Lines changed: 89 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ def lifecycle_approve_for_my_org(self, orderer_url, channel_name, cc_name,
118118
The administrator can use the peer lifecycle chaincode approveformyorg subcommand to approve the chain code on
119119
behalf of the organization.
120120
:param orderer_url: orderer accessable url
121-
:param orderer_tls_rootcert: orderer tls certificate
122121
:param channel_name: channel name
123122
:param cc_name: chaincode name
124123
:param chaincode_version: chaincode version
@@ -215,96 +214,113 @@ def lifecycle_query_approved(self, channel_name, cc_name):
215214

216215
return return_code, chaincodes_info
217216

218-
def lifecycle_check_commit_readiness(self, orderer_url, orderer_tls_rootcert, channel_name, cc_name, cc_version,
219-
policy, sequence=1):
217+
def lifecycle_check_commit_readiness(self, channel_name, cc_name, cc_version, sequence=1):
220218
"""
221-
222-
:param orderer_url:orderer accessable url
223-
:param orderer_tls_rootcert:orderer tls certificate
224219
:param channel_name:channel name
225220
:param cc_name: chaincode name
226221
:param cc_version: chaincode version
227-
:param policy:chaincode policy
228222
:param sequence:The channel chain code defines the serial number. The default value is 1
229223
:return:
230224
"""
231225
try:
226+
ORDERER_CA = os.getenv("ORDERER_CA")
227+
command = []
232228
if os.getenv("CORE_PEER_TLS_ENABLED") == "false" or os.getenv("CORE_PEER_TLS_ENABLED") is None:
233-
res = subprocess.Popen("{} lifecycle chaincode checkcommitreadiness --output json "
234-
" --channelID {} --name {} --version {} --init-required --sequence {} "
235-
"--signature-policy {}"
236-
.format(self.peer, channel_name, cc_name, cc_version, sequence, policy),
237-
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
238-
stdout, stderr = res.communicate()
239-
return_code = res.returncode
240-
if return_code == 0:
241-
content = str(stdout, encoding="utf-8")
242-
chaincodes_info = json.loads(content)
243-
return return_code, chaincodes_info
244-
else:
245-
stderr = str(stderr, encoding="utf-8")
246-
return return_code, stderr
229+
command = [
230+
self.peer,
231+
"lifecycle", "chaincode", "checkcommitreadiness",
232+
"--channelID", channel_name,
233+
"--name", cc_name,
234+
"--version", cc_version,
235+
"--sequence", str(sequence),
236+
"--output", "json",
237+
]
247238
else:
248-
res = subprocess.Popen("{} lifecycle chaincode checkcommitreadiness --output json "
249-
"-o {} --tls --cafile {} --channelID {} --name {} --version {} "
250-
"--signature-policy {} --init-required --sequence {}"
251-
.format(self.peer, orderer_url, orderer_tls_rootcert, channel_name, cc_name,
252-
cc_version, policy, sequence),
253-
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
254-
stdout, stderr = res.communicate()
255-
return_code = res.returncode
256-
if return_code == 0:
257-
content = str(stdout, encoding="utf-8")
258-
chaincodes_info = json.loads(content)
259-
return return_code, chaincodes_info
260-
else:
261-
stderr = str(stderr, encoding="utf-8")
262-
return return_code, stderr
239+
command = [
240+
self.peer,
241+
"lifecycle", "chaincode", "checkcommitreadiness",
242+
"--channelID", channel_name,
243+
"--name", cc_name,
244+
"--version", cc_version,
245+
"--sequence", str(sequence),
246+
"--tls",
247+
"--cafile", ORDERER_CA,
248+
"--output", "json",
249+
]
250+
251+
LOG.info(" ".join(command))
252+
253+
res = subprocess.Popen(command, shell=False,
254+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
255+
stdout, stderr = res.communicate()
256+
return_code = res.returncode
257+
if return_code == 0:
258+
content = str(stdout, encoding="utf-8")
259+
chaincodes_info = json.loads(content)
260+
return return_code, chaincodes_info
261+
else:
262+
stderr = str(stderr, encoding="utf-8")
263+
return return_code, stderr
263264
except Exception as e:
264-
err_msg = "lifecycle_check_commit_readiness failed for {}!".format(
265-
e)
265+
err_msg = "lifecycle_check_commit_readiness failed for {}!".format(e)
266266
raise Exception(err_msg)
267267

268-
def lifecycle_commit(self, orderer_url, orderer_tls_rootcert, channel_name, cc_name, chaincode_version,
269-
policy, peerlist, peer_root_certs, sequency=1):
268+
def lifecycle_commit(self, orderer_url, channel_name, cc_name, chaincode_version, sequence, policy, peer_list=[], peer_root_certs=[], init_flag=False):
270269
"""
271270
The administrator can submit the chain code definition to the specified channel by using the peer lifecycle
272271
chain code commit subcommand
273272
:param orderer_url: orderer accessable url
274-
:param orderer_tls_rootcert:orderer tls certificate
275273
:param channel_name:channel name
276274
:param cc_name:chaincode name
277275
:param chaincode_version:chaincode version
276+
:param sequence:The channel chain code defines the serial number. The default value is 1
278277
:param policy:chaincode policy
279-
:param peerlist: the list of peerAddress
278+
:param peer_list: the list of peerAddress
280279
:param peer_root_certs: the list of peer_root_certs, the orderer should be same as peerlist's.
281-
:param sequency:The channel chain code defines the serial number. The default value is 1
280+
:param init_flag:if the chaincode is first init.
282281
:return:
283282
"""
284283
try:
285-
peer_addresses_format = " --peerAddresses {} --tlsRootCertFiles {}"
286-
command_str_with_tls = "{} lifecycle chaincode commit -o {} --tls --cafile {} " \
287-
"--channelID {} --name {} --version {} --init-required --sequence {} " \
288-
"--signature-policy {}"
289-
command_str_without_tls = "{} lifecycle chaincode commit -o {} --channelID {} --name {} " \
290-
"--version {} --init-required --sequence {} --signature-policy {}"
291-
292-
peer_addressed = []
293-
for i in range(len(peerlist)):
294-
peer_addressed.append(peerlist[i])
295-
peer_addressed.append(peer_root_certs[i])
284+
command = []
296285
if os.getenv("CORE_PEER_TLS_ENABLED") == "false" or os.getenv("CORE_PEER_TLS_ENABLED") is None:
297-
for i in range(len(peerlist)):
298-
command_str_without_tls = command_str_without_tls + peer_addresses_format
299-
res = os.system(command_str_without_tls.format(self.peer, orderer_url, channel_name, cc_name,
300-
chaincode_version, sequency, policy, *peer_addressed)) # --collections-config {}
286+
command = [
287+
self.peer,
288+
"lifecycle", "chaincode", "commit",
289+
"-o", orderer_url,
290+
"--channelID", channel_name,
291+
"--name", cc_name,
292+
"--version", chaincode_version,
293+
"--sequence", str(sequence),
294+
]
301295
else:
302-
for i in range(len(peerlist)):
303-
command_str_with_tls = command_str_with_tls + peer_addresses_format
304-
305-
res = os.system(command_str_with_tls.format(self.peer, orderer_url, orderer_tls_rootcert, channel_name,
306-
cc_name, chaincode_version, sequency, policy, *peer_addressed))
296+
ORDERER_CA = os.getenv("ORDERER_CA")
297+
command = [
298+
self.peer,
299+
"lifecycle", "chaincode", "commit",
300+
"-o", orderer_url,
301+
"--ordererTLSHostnameOverride", orderer_url.split(":")[0],
302+
"--channelID", channel_name,
303+
"--name", cc_name,
304+
"--version", chaincode_version,
305+
"--sequence", str(sequence),
306+
"--tls",
307+
"--cafile", ORDERER_CA,
308+
]
307309

310+
for i in range(len(peer_list)):
311+
command.append("--peerAddresses")
312+
command.append(peer_list[i])
313+
command.append("--tlsRootCertFiles")
314+
command.append(peer_root_certs[i])
315+
316+
if init_flag:
317+
command.append("--init-required")
318+
if policy:
319+
command.append("--signature-policy")
320+
command.append(policy)
321+
322+
LOG.info(" ".join(command))
323+
res = os.system(" ".join(command))
308324
res = res >> 8
309325
return res
310326

@@ -320,10 +336,16 @@ def lifecycle_query_committed(self, channel_name, cc_name):
320336
:return: chaincodes info has commited in channel of the cc_name
321337
"""
322338
try:
323-
res = subprocess.Popen("{} lifecycle chaincode querycommitted --channelID {} "
324-
"--output json --name {}".format(
325-
self.peer, channel_name, cc_name),
326-
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
339+
command = [
340+
self.peer,
341+
"lifecycle", "chaincode", "querycommitted",
342+
"--channelID", channel_name,
343+
"--output", "json",
344+
"--name", cc_name,
345+
]
346+
LOG.info(" ".join(command))
347+
res = subprocess.Popen(command, shell=False,
348+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
327349
stdout, stderr = res.communicate()
328350
return_code = res.returncode
329351
if return_code == 0:

src/api-engine/api/routes/chaincode/serializers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,4 @@ class ChainCodeApproveForMyOrgBody(serializers.Serializer):
6868

6969

7070
class ChainCodeCommitBody(ChainCodeApproveForMyOrgBody):
71-
peer_list = serializers.ListField(allow_empty=False, required=True)
71+
pass

src/api-engine/api/routes/chaincode/views.py

Lines changed: 90 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
from api.config import CELLO_HOME
1717
from api.models import (
1818
Node,
19-
ChainCode
19+
ChainCode,
20+
Channel
2021
)
2122
from api.utils.common import make_uuid
2223
from django.core.paginator import Paginator
@@ -495,61 +496,114 @@ def commit(self, request):
495496
try:
496497
channel_name = serializer.validated_data.get("channel_name")
497498
chaincode_name = serializer.validated_data.get("chaincode_name")
498-
chaincode_version = serializer.validated_data.get(
499-
"chaincode_version")
499+
chaincode_version = serializer.validated_data.get("chaincode_version")
500500
policy = serializer.validated_data.get("policy")
501-
# Perhaps the orderer's port is best stored in the database
502-
orderer_url = serializer.validated_data.get("orderer_url")
503501
sequence = serializer.validated_data.get("sequence")
504-
peer_list = serializer.validated_data.get("peer_list")
502+
init_flag = serializer.validated_data.get("init_flag", False)
503+
505504
org = request.user.organization
506505
qs = Node.objects.filter(type="orderer", organization=org)
507506
if not qs.exists():
508507
raise ResourceNotFound("Orderer Does Not Exist")
509508
orderer_node = qs.first()
509+
orderer_url = orderer_node.name + "." + org.name.split(".", 1)[1] + ":" + str(7050)
510510

511-
orderer_tls_dir = "{}/{}/crypto-config/ordererOrganizations/{}/orderers/{}/msp/tlscacerts" \
512-
.format(CELLO_HOME, org.name, org.name.split(".", 1)[1], orderer_node.name + "." +
513-
org.name.split(".", 1)[1])
514-
orderer_tls_root_cert = ""
515-
for _, _, files in os.walk(orderer_tls_dir):
516-
orderer_tls_root_cert = orderer_tls_dir + "/" + files[0]
517-
break
518-
511+
# Step 1: Check commit readiness, find all approved organizations
519512
qs = Node.objects.filter(type="peer", organization=org)
520513
if not qs.exists():
521514
raise ResourceNotFound("Peer Does Not Exist")
522515
peer_node = qs.first()
523516
envs = init_env_vars(peer_node, org)
524-
525-
peer_root_certs = []
517+
518+
peer_channel_cli = PeerChainCode(**envs)
519+
code, readiness_result = peer_channel_cli.lifecycle_check_commit_readiness(
520+
channel_name, chaincode_name, chaincode_version, sequence)
521+
if code != 0:
522+
return Response(err(f"Check commit readiness failed: {readiness_result}"),
523+
status=status.HTTP_400_BAD_REQUEST)
524+
525+
# Check approved status
526+
approvals = readiness_result.get("approvals", {})
527+
approved_orgs = [org_msp for org_msp, approved in approvals.items() if approved]
528+
if not approved_orgs:
529+
return Response(err("No organizations have approved this chaincode"),
530+
status=status.HTTP_400_BAD_REQUEST)
531+
532+
LOG.info(f"Approved organizations: {approved_orgs}")
533+
534+
# Step 2: Get channel organizations and peer nodes
535+
try:
536+
channel = Channel.objects.get(name=channel_name)
537+
channel_orgs = channel.organizations.all()
538+
except Channel.DoesNotExist:
539+
return Response(err(f"Channel {channel_name} not found"),
540+
status=status.HTTP_400_BAD_REQUEST)
541+
542+
# find the corresponding organization by MSP ID
543+
# MSP ID format: Org1MSP, Org2MSP -> organization name format: org1.xxx, org2.xxx
544+
approved_organizations = []
545+
for msp_id in approved_orgs:
546+
if msp_id.endswith("MSP"):
547+
org_prefix = msp_id[:-3].lower() # remove "MSP" and convert to lowercase
548+
# find the corresponding organization in the channel
549+
for channel_org in channel_orgs:
550+
if channel_org.name.split(".")[0] == org_prefix:
551+
approved_organizations.append(channel_org)
552+
LOG.info(f"Found approved organization: {channel_org.name} (MSP: {msp_id})")
553+
break
554+
555+
if not approved_organizations:
556+
return Response(err("No approved organizations found in this channel"),
557+
status=status.HTTP_400_BAD_REQUEST)
558+
559+
# get peer nodes and root certs
526560
peer_address_list = []
527-
for each in peer_list:
528-
peer_node = Node.objects.get(id=each)
529-
peer_tls_cert = "{}/{}/crypto-config/peerOrganizations/{}/peers/{}/tls/ca.crt" \
530-
.format(CELLO_HOME, org.name, org.name, peer_node.name + "." + org.name)
531-
print(peer_node.port)
532-
# port = peer_node.port.all()[0].internal
533-
# port = ports[0].internal
534-
peer_address = peer_node.name + \
535-
"." + org.name + ":" + str(7051)
536-
peer_address_list.append(peer_address)
537-
peer_root_certs.append(peer_tls_cert)
561+
peer_root_certs = []
562+
563+
for approved_org in approved_organizations:
564+
org_peer_nodes = Node.objects.filter(type="peer", organization=approved_org)
565+
if org_peer_nodes.exists():
566+
# select the first peer node for each organization
567+
peer = org_peer_nodes.first()
568+
peer_tls_cert = "{}/{}/crypto-config/peerOrganizations/{}/peers/{}/tls/ca.crt" \
569+
.format(CELLO_HOME, approved_org.name, approved_org.name,
570+
peer.name + "." + approved_org.name)
571+
peer_address = peer.name + "." + approved_org.name + ":" + str(7051)
572+
peer_address_list.append(peer_address)
573+
peer_root_certs.append(peer_tls_cert)
574+
LOG.info(f"Added peer from approved org {approved_org.name}: {peer_address}")
575+
else:
576+
LOG.warning(f"No peer nodes found for approved organization: {approved_org.name}")
538577

539-
peer_channel_cli = PeerChainCode(**envs)
540-
code = peer_channel_cli.lifecycle_commit(orderer_url, orderer_tls_root_cert, channel_name,
541-
chaincode_name, chaincode_version, policy,
542-
peer_address_list, peer_root_certs, sequence)
578+
if not peer_address_list:
579+
return Response(err("No peer nodes found for approved organizations"),
580+
status=status.HTTP_400_BAD_REQUEST)
581+
582+
# Step 3: Commit chaincode
583+
code = peer_channel_cli.lifecycle_commit(
584+
orderer_url, channel_name, chaincode_name, chaincode_version,
585+
sequence, policy, peer_address_list, peer_root_certs, init_flag)
543586
if code != 0:
544-
return Response(err("commit failed."), status=status.HTTP_400_BAD_REQUEST)
587+
return Response(err("Commit chaincode failed"),
588+
status=status.HTTP_400_BAD_REQUEST)
589+
590+
LOG.info(f"Chaincode {chaincode_name} committed successfully")
591+
592+
# Step 4: Query committed chaincode
593+
code, committed_result = peer_channel_cli.lifecycle_query_committed(
594+
channel_name, chaincode_name)
595+
if code == 0:
596+
LOG.info(committed_result)
597+
return Response(ok(committed_result), status=status.HTTP_200_OK)
598+
else:
599+
return Response(err("Query committed failed."), status=status.HTTP_400_BAD_REQUEST)
545600

546601
except Exception as e:
602+
LOG.error(f"Commit chaincode failed: {str(e)}")
547603
return Response(
548-
err(e.args), status=status.HTTP_400_BAD_REQUEST
604+
err(f"Commit chaincode failed: {str(e)}"),
605+
status=status.HTTP_400_BAD_REQUEST
549606
)
550-
return Response(
551-
ok("commit success."), status=status.HTTP_200_OK
552-
)
553607

554608
@swagger_auto_schema(
555609
method="get",

0 commit comments

Comments
 (0)