From e8e29607370e95ef4b19ef0666dcb7ce6026c3e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=AF=E5=98=89=E9=A2=96?= <568296125@qq.com> Date: Wed, 3 Jun 2026 23:29:09 +0800 Subject: [PATCH] [fix][committeeptc][node] match anchor BTA by init state --- .../EndorseServiceRepositoryImpl.java | 69 +++++++++++++++++-- .../repository/SystemConfigRepository.java | 28 +++++--- .../interfaces/IEndorseServiceRepository.java | 4 ++ .../service/impl/EndorserServiceImpl.java | 36 +++++++--- .../dal/EndorseServiceRepositoryTest.java | 3 + .../node/dal/SystemConfigRepositoryTest.java | 6 ++ .../node/server/CommitteeNodeServiceTest.java | 6 ++ .../node/service/EndorserServiceTest.java | 5 ++ 8 files changed, 134 insertions(+), 23 deletions(-) diff --git a/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/dal/repository/EndorseServiceRepositoryImpl.java b/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/dal/repository/EndorseServiceRepositoryImpl.java index 8520acc8..69dd880b 100644 --- a/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/dal/repository/EndorseServiceRepositoryImpl.java +++ b/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/dal/repository/EndorseServiceRepositoryImpl.java @@ -21,6 +21,7 @@ import java.util.List; import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import com.alipay.antchain.bridge.commons.core.base.CrossChainLane; import com.alipay.antchain.bridge.ptc.committee.node.commons.exception.DataAccessLayerException; @@ -86,6 +87,26 @@ public TpBtaWrapper getMatchedTpBta(CrossChainLane lane, int tpbtaVersion) { } } + @Override + public TpBtaWrapper getMatchedTpBta(CrossChainLane lane, int tpbtaVersion, int btaSubjectVersion) { + try { + var entityList = searchTpBta(lane, tpbtaVersion).stream() + .filter(entity -> entity.getBtaSubjectVersion() == btaSubjectVersion) + .toList(); + if (ObjectUtil.isEmpty(entityList)) { + return null; + } + return ConvertUtil.convertFrom( + entityList.stream().max(Comparator.comparingInt(TpBtaEntity::getTpbtaVersion)).get() + ); + } catch (Exception e) { + throw new DataAccessLayerException( + e, "Failed to get tpbta for lane {}, version {} and bta subject version {}", + lane.getLaneKey(), tpbtaVersion, btaSubjectVersion + ); + } + } + @Override public TpBtaWrapper getExactTpBta(CrossChainLane lane) { return getExactTpBta(lane, -1); @@ -117,14 +138,19 @@ public TpBtaWrapper getExactTpBta(CrossChainLane lane, int tpbtaVersion) { @Override public void setTpBta(TpBtaWrapper tpBtaWrapper) { + var lane = tpBtaWrapper.getCrossChainLane(); + var tpbtaVersion = tpBtaWrapper.getTpbta().getTpbtaVersion(); try { - if (hasTpBta(tpBtaWrapper.getCrossChainLane(), tpBtaWrapper.getTpbta().getTpbtaVersion())) { - throw new RuntimeException("tpBta already exists"); + if (hasTpBta(lane, tpbtaVersion)) { + return; } tpBtaMapper.insert((TpBtaEntity) ConvertUtil.convertFrom(tpBtaWrapper)); } catch (Exception e) { + if (hasTpBta(lane, tpbtaVersion)) { + return; + } throw new DataAccessLayerException( - e, "Failed to save tpbta for lane {}", tpBtaWrapper.getCrossChainLane().getLaneKey() + e, "Failed to save tpbta for lane {}", lane.getLaneKey() ); } } @@ -186,14 +212,42 @@ public BtaWrapper getBta(String domain, int subjectVersion) { } } + @Override + public BtaWrapper getBta(String domain, BigInteger initHeight, byte[] initBlockHash) { + try { + var entityList = btaMapper.selectList( + new LambdaQueryWrapper() + .eq(BtaEntity::getDomain, domain) + ); + if (ObjectUtil.isEmpty(entityList)) { + return null; + } + return entityList.stream() + .map(ConvertUtil::convertFrom) + .map(BtaWrapper.class::cast) + .filter(wrapper -> wrapper.getBta().getInitHeight().equals(initHeight)) + .filter(wrapper -> ArrayUtil.equals(wrapper.getBta().getInitBlockHash(), initBlockHash)) + .max(Comparator.comparingInt(BtaWrapper::getSubjectVersion)) + .orElse(null); + } catch (Exception e) { + throw new DataAccessLayerException( + e, "Failed to get bta for domain {}, init height {} and init block hash {}", + domain, initHeight, initBlockHash + ); + } + } + @Override public void setBta(BtaWrapper btaWrapper) { try { - if (hasBta(btaWrapper.getDomain(), btaWrapper.getBtaVersion())) { - throw new RuntimeException("bta already exists"); + if (hasBta(btaWrapper.getDomain(), btaWrapper.getSubjectVersion())) { + return; } btaMapper.insert((BtaEntity) ConvertUtil.convertFrom(btaWrapper)); } catch (Exception e) { + if (hasBta(btaWrapper.getDomain(), btaWrapper.getSubjectVersion())) { + return; + } throw new DataAccessLayerException( e, "Failed to save bta for domain {} and subject version {}", btaWrapper.getDomain(), btaWrapper.getSubjectVersion() ); @@ -272,10 +326,13 @@ public ValidatedConsensusStateWrapper getValidatedConsensusState(String domain, public void setValidatedConsensusState(ValidatedConsensusStateWrapper validatedConsensusStateWrapper) { try { if (hasValidatedConsensusState(validatedConsensusStateWrapper.getDomain(), validatedConsensusStateWrapper.getHeight())) { - throw new RuntimeException("validated consensus state already exists"); + return; } validatedConsensusStatesMapper.insert((ValidatedConsensusStatesEntity) ConvertUtil.convertFrom(validatedConsensusStateWrapper)); } catch (Exception e) { + if (hasValidatedConsensusState(validatedConsensusStateWrapper.getDomain(), validatedConsensusStateWrapper.getHeight())) { + return; + } throw new DataAccessLayerException( e, "Failed to save validated consensus state for domain {} and height {}", validatedConsensusStateWrapper.getDomain(), diff --git a/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/dal/repository/SystemConfigRepository.java b/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/dal/repository/SystemConfigRepository.java index 5d79f0e1..0d52db37 100644 --- a/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/dal/repository/SystemConfigRepository.java +++ b/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/dal/repository/SystemConfigRepository.java @@ -29,6 +29,7 @@ import com.alipay.antchain.bridge.ptc.committee.node.dal.mapper.SystemConfigMapper; import com.alipay.antchain.bridge.ptc.committee.node.dal.repository.interfaces.ISystemConfigRepository; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import jakarta.annotation.Resource; import lombok.Synchronized; import org.springframework.stereotype.Component; @@ -79,14 +80,7 @@ public boolean hasSystemConfig(String key) { @Override public void setSystemConfig(Map configs) { try { - configs.forEach((key, value) -> { - systemConfigMapper.insert( - SystemConfigEntity.builder() - .confKey(key) - .confValue(value) - .build() - ); - }); + configs.forEach(this::setSystemConfig); } catch (Exception e) { throw new DataAccessLayerException( e, "Failed to set system config with key: {}", JSON.toJSONString(configs) @@ -98,6 +92,10 @@ public void setSystemConfig(Map configs) { @Synchronized public void setSystemConfig(String key, String value) { try { + if (hasSystemConfig(key)) { + updateSystemConfig(key, value); + return; + } systemConfigMapper.insert( SystemConfigEntity.builder() .confKey(key) @@ -105,6 +103,10 @@ public void setSystemConfig(String key, String value) { .build() ); } catch (Exception e) { + if (hasSystemConfig(key)) { + updateSystemConfig(key, value); + return; + } throw new DataAccessLayerException( e, "Failed to set system config with key: {}", key ); @@ -135,4 +137,14 @@ public void setPtcTrustRoot(PTCTrustRoot ptcTrustRoot) { public PTCTrustRoot getPtcTrustRoot() { return PTCTrustRoot.decode(Base64.decode(getSystemConfig(CURRENT_PTC_TRUST_ROOT))); } + + private void updateSystemConfig(String key, String value) { + systemConfigMapper.update( + SystemConfigEntity.builder() + .confValue(value) + .build(), + new LambdaUpdateWrapper() + .eq(SystemConfigEntity::getConfKey, key) + ); + } } diff --git a/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/dal/repository/interfaces/IEndorseServiceRepository.java b/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/dal/repository/interfaces/IEndorseServiceRepository.java index b98fc799..048814db 100644 --- a/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/dal/repository/interfaces/IEndorseServiceRepository.java +++ b/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/dal/repository/interfaces/IEndorseServiceRepository.java @@ -29,6 +29,8 @@ public interface IEndorseServiceRepository { TpBtaWrapper getMatchedTpBta(CrossChainLane lane, int tpbtaVersion); + TpBtaWrapper getMatchedTpBta(CrossChainLane lane, int tpbtaVersion, int btaSubjectVersion); + TpBtaWrapper getExactTpBta(CrossChainLane lane); TpBtaWrapper getExactTpBta(CrossChainLane lane, int tpbtaVersion); @@ -41,6 +43,8 @@ public interface IEndorseServiceRepository { BtaWrapper getBta(String domain, int subjectVersion); + BtaWrapper getBta(String domain, BigInteger initHeight, byte[] initBlockHash); + void setBta(BtaWrapper btaWrapper); boolean hasBta(String domain, int subjectVersion); diff --git a/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/service/impl/EndorserServiceImpl.java b/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/service/impl/EndorserServiceImpl.java index f7ffc200..9dfe9bb2 100644 --- a/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/service/impl/EndorserServiceImpl.java +++ b/acb-committeeptc/node/src/main/java/com/alipay/antchain/bridge/ptc/committee/node/service/impl/EndorserServiceImpl.java @@ -138,15 +138,26 @@ public TpBtaWrapper verifyBta(AbstractCrossChainCertificate domainCert, IBlockch throw new InvalidBtaException("tpbta intersection check failed"); } + var committeeEndorseRoot = verifyBtaExtension.getCommitteeEndorseRoot().encode(); + var currentPtcAnchorVersion = systemConfigRepository.queryCurrentPtcAnchorVersion(); var latestTpBta = endorseServiceRepository.getExactTpBta(verifyBtaExtension.getCrossChainLane()); + var tpbtaVersion = ObjectUtil.isNull(latestTpBta) ? 1 : latestTpBta.getTpbta().getTpbtaVersion() + 1; + if ( + ObjectUtil.isNotNull(latestTpBta) + && latestTpBta.getTpbta().getBtaSubjectVersion() == bta.getSubjectVersion() + && ObjectUtil.equals(latestTpBta.getTpbta().getPtcVerifyAnchorVersion(), currentPtcAnchorVersion) + && ArrayUtil.equals(latestTpBta.getTpbta().getEndorseRoot(), committeeEndorseRoot) + ) { + tpbtaVersion = latestTpBta.getTpbta().getTpbtaVersion(); + } var tpbta = new ThirdPartyBlockchainTrustAnchorV1( - ObjectUtil.isNull(latestTpBta) ? 1 : latestTpBta.getTpbta().getTpbtaVersion() + 1, - systemConfigRepository.queryCurrentPtcAnchorVersion(), + tpbtaVersion, + currentPtcAnchorVersion, (PTCCredentialSubject) ptcCrossChainCert.getCredentialSubjectInstance(), verifyBtaExtension.getCrossChainLane(), bta.getSubjectVersion(), ucpHashAlgo, - verifyBtaExtension.getCommitteeEndorseRoot().encode(), + committeeEndorseRoot, new byte[]{} ); tpbta.setEndorseProof( @@ -177,13 +188,20 @@ private boolean checkIfTpBTAIntersection(CrossChainLane tpbtaLane) { @Override public ValidatedConsensusState commitAnchorState(CrossChainLane crossChainLane, ConsensusState anchorState) { - var tpbta = endorseServiceRepository.getMatchedTpBta(crossChainLane); - if (ObjectUtil.isNull(tpbta)) { - throw new InvalidConsensusStateException("tpbta not found for {}", crossChainLane.getLaneKey()); - } - var bta = endorseServiceRepository.getBta(crossChainLane.getSenderDomain().getDomain(), tpbta.getTpbta().getBtaSubjectVersion()); + var bta = endorseServiceRepository.getBta( + anchorState.getDomain().getDomain(), + anchorState.getHeight(), + anchorState.getHash() + ); if (ObjectUtil.isNull(bta)) { - throw new InvalidConsensusStateException("bta not found for {}", crossChainLane.getSenderDomain().getDomain()); + throw new InvalidConsensusStateException("bta not found for domain {}, height {} and hash {}", + anchorState.getDomain().getDomain(), anchorState.getHeight().toString(), anchorState.getHashHex()); + } + + var tpbta = endorseServiceRepository.getMatchedTpBta(crossChainLane, -1, bta.getSubjectVersion()); + if (ObjectUtil.isNull(tpbta)) { + throw new InvalidConsensusStateException("tpbta not found for {} and bta subject version {}", + crossChainLane.getLaneKey(), bta.getSubjectVersion()); } var hcdvs = hcdvsPluginService.getHCDVSService(bta.getProduct()); diff --git a/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/dal/EndorseServiceRepositoryTest.java b/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/dal/EndorseServiceRepositoryTest.java index 839bb0af..6f437133 100644 --- a/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/dal/EndorseServiceRepositoryTest.java +++ b/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/dal/EndorseServiceRepositoryTest.java @@ -73,6 +73,7 @@ public void testBta() { var btaWrapper = new BtaWrapper(); btaWrapper.setBta(bta); endorseServiceRepository.setBta(btaWrapper); + endorseServiceRepository.setBta(btaWrapper); var btaWrapperFromDB = endorseServiceRepository.getBta(btaWrapper.getDomain()); Assert.assertEquals( @@ -122,6 +123,7 @@ public void testTpBta() { ); var tpBtaWrapper = new TpBtaWrapper(tpbta); + endorseServiceRepository.setTpBta(tpBtaWrapper); endorseServiceRepository.setTpBta(tpBtaWrapper); Assert.assertNotNull(endorseServiceRepository.getMatchedTpBta(crossChainLane)); @@ -143,6 +145,7 @@ public void testValidatedConsensusState() { ); var vcs = BeanUtil.copyProperties(cs, ValidatedConsensusStateV1.class); + endorseServiceRepository.setValidatedConsensusState(new ValidatedConsensusStateWrapper(vcs)); endorseServiceRepository.setValidatedConsensusState(new ValidatedConsensusStateWrapper(vcs)); Assert.assertTrue(endorseServiceRepository.hasValidatedConsensusState("test", BigInteger.valueOf(100L))); diff --git a/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/dal/SystemConfigRepositoryTest.java b/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/dal/SystemConfigRepositoryTest.java index 36e008d3..9853c33c 100644 --- a/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/dal/SystemConfigRepositoryTest.java +++ b/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/dal/SystemConfigRepositoryTest.java @@ -69,5 +69,11 @@ public void testSystemConfig() { "test", systemConfigRepository.getSystemConfig("test") ); + + systemConfigRepository.setSystemConfig("test", "test2"); + Assert.assertEquals( + "test2", + systemConfigRepository.getSystemConfig("test") + ); } } diff --git a/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/server/CommitteeNodeServiceTest.java b/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/server/CommitteeNodeServiceTest.java index 42eb3937..b94d8cff 100644 --- a/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/server/CommitteeNodeServiceTest.java +++ b/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/server/CommitteeNodeServiceTest.java @@ -65,6 +65,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -347,7 +348,9 @@ public void testCommitAnchorState() { var hcdvs = mock(IHeteroChainDataVerifierService.class); when(hcdvs.verifyAnchorConsensusState(any(), any())).thenReturn(VerifyResult.builder().success(true).build()); when(endorseServiceRepository.getMatchedTpBta(any())).thenReturn(new TpBtaWrapper(tpbta)); + when(endorseServiceRepository.getMatchedTpBta(any(), anyInt(), anyInt())).thenReturn(new TpBtaWrapper(tpbta)); when(endorseServiceRepository.getBta(anyString())).thenReturn(new BtaWrapper(bta)); + when(endorseServiceRepository.getBta(anyString(), any(), any())).thenReturn(new BtaWrapper(bta)); when(hcdvsPluginService.getHCDVSService(anyString())).thenReturn(hcdvs); var vcs = BeanUtil.copyProperties(anchorState, ValidatedConsensusStateV1.class); @@ -397,7 +400,9 @@ public void testCommitConsensusState() { when(hcdvs.verifyConsensusState(any(), any())).thenReturn(VerifyResult.builder().success(true).build()); when(endorseServiceRepository.getMatchedTpBta(any())).thenReturn(new TpBtaWrapper(tpbta)); when(endorseServiceRepository.getBta(anyString())).thenReturn(new BtaWrapper(bta)); + when(endorseServiceRepository.getBta(anyString(), anyInt())).thenReturn(new BtaWrapper(bta)); when(endorseServiceRepository.getValidatedConsensusState(anyString(), anyString())).thenReturn(new ValidatedConsensusStateWrapper(vcs)); + when(endorseServiceRepository.getValidatedConsensusState(anyString(), any(BigInteger.class))).thenReturn(new ValidatedConsensusStateWrapper(vcs)); when(hcdvsPluginService.getHCDVSService(anyString())).thenReturn(hcdvs); StreamRecorder responseObserver = StreamRecorder.create(); @@ -438,6 +443,7 @@ public void testVerifyCrossChainMessage() { when(hcdvs.parseMessageFromLedgerData(any())).thenReturn(ucp.getSrcMessage().getMessage()); when(endorseServiceRepository.getExactTpBta(any())).thenReturn(new TpBtaWrapper(tpbta)); when(endorseServiceRepository.getBta(anyString())).thenReturn(new BtaWrapper(bta)); + when(endorseServiceRepository.getBta(anyString(), anyInt())).thenReturn(new BtaWrapper(bta)); when(endorseServiceRepository.getValidatedConsensusState(anyString(), anyString())).thenReturn(new ValidatedConsensusStateWrapper(currVcs)); when(hcdvsPluginService.getHCDVSService(anyString())).thenReturn(hcdvs); diff --git a/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/service/EndorserServiceTest.java b/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/service/EndorserServiceTest.java index 6c64d69e..68d399ec 100644 --- a/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/service/EndorserServiceTest.java +++ b/acb-committeeptc/node/src/test/java/com/alipay/antchain/bridge/ptc/committee/node/service/EndorserServiceTest.java @@ -280,7 +280,9 @@ public void testCommitAnchorState() { var hcdvs = mock(IHeteroChainDataVerifierService.class); when(hcdvs.verifyAnchorConsensusState(any(), any())).thenReturn(VerifyResult.builder().success(true).build()); when(endorseServiceRepository.getMatchedTpBta(any())).thenReturn(new TpBtaWrapper(tpbta)); + when(endorseServiceRepository.getMatchedTpBta(any(), anyInt(), anyInt())).thenReturn(new TpBtaWrapper(tpbta)); when(endorseServiceRepository.getBta(anyString())).thenReturn(new BtaWrapper(bta)); + when(endorseServiceRepository.getBta(anyString(), any(), any())).thenReturn(new BtaWrapper(bta)); when(hcdvsPluginService.getHCDVSService(anyString())).thenReturn(hcdvs); var vcs = BeanUtil.copyProperties(anchorState, ValidatedConsensusStateV1.class); @@ -313,7 +315,9 @@ public void testCommitConsensusState() { when(hcdvs.verifyConsensusState(any(), any())).thenReturn(VerifyResult.builder().success(true).build()); when(endorseServiceRepository.getMatchedTpBta(any())).thenReturn(new TpBtaWrapper(tpbta)); when(endorseServiceRepository.getBta(anyString())).thenReturn(new BtaWrapper(bta)); + when(endorseServiceRepository.getBta(anyString(), anyInt())).thenReturn(new BtaWrapper(bta)); when(endorseServiceRepository.getValidatedConsensusState(anyString(), anyString())).thenReturn(new ValidatedConsensusStateWrapper(vcs)); + when(endorseServiceRepository.getValidatedConsensusState(anyString(), any(BigInteger.class))).thenReturn(new ValidatedConsensusStateWrapper(vcs)); when(hcdvsPluginService.getHCDVSService(anyString())).thenReturn(hcdvs); var vcsSigned = endorserService.commitConsensusState(crossChainLane, currState); @@ -337,6 +341,7 @@ public void testVerifyUcp() { when(hcdvs.parseMessageFromLedgerData(any())).thenReturn(ucp.getSrcMessage().getMessage()); when(endorseServiceRepository.getExactTpBta(any())).thenReturn(new TpBtaWrapper(tpbta)); when(endorseServiceRepository.getBta(anyString())).thenReturn(new BtaWrapper(bta)); + when(endorseServiceRepository.getBta(anyString(), anyInt())).thenReturn(new BtaWrapper(bta)); when(endorseServiceRepository.getValidatedConsensusState(anyString(), anyString())).thenReturn(new ValidatedConsensusStateWrapper(currVcs)); when(hcdvsPluginService.getHCDVSService(anyString())).thenReturn(hcdvs);