Skip to content

Commit

Permalink
Merge pull request #33 from AntChainOpenLabs/feat/sdpv2_upgrade
Browse files Browse the repository at this point in the history
Feat/sdpv2 upgrade
  • Loading branch information
zouxyan authored Apr 17, 2024
2 parents 7023d6d + 575c5c6 commit 785a5c2
Show file tree
Hide file tree
Showing 26 changed files with 1,168 additions and 90 deletions.
2 changes: 1 addition & 1 deletion antchain-bridge-bcdns/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.alipay.antchain.bridge</groupId>
<artifactId>antchain-bridge-bcdns</artifactId>
<version>0.2.1</version>
<version>0.2.2</version>

<properties>
<maven.compiler.source>8</maven.compiler.source>
Expand Down
2 changes: 1 addition & 1 deletion antchain-bridge-commons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.alipay.antchain.bridge</groupId>
<artifactId>antchain-bridge-commons</artifactId>
<version>0.2.1</version>
<version>0.2.2</version>

<properties>
<maven.compiler.source>8</maven.compiler.source>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,10 @@ public byte[] getPayload() {
}

abstract void setPayload(byte[] payload);

public abstract void setNonce(long nonce);

public abstract void setAtomicFlag(AtomicFlagEnum atomicFlag);

public abstract void setMessageId(SDPMessageId messageId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.alipay.antchain.bridge.commons.core.sdp;

import cn.hutool.core.util.ByteUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alipay.antchain.bridge.commons.exception.AntChainBridgeCommonsException;
import com.alipay.antchain.bridge.commons.exception.CommonsErrorCodeEnum;
import lombok.Getter;

/**
* Enum {@code AtomicFlagEnum} gives all types for SDP packet.
*/
@Getter
public enum AtomicFlagEnum {

/**
* {@code NONE_ATOMIC} means that this request has no atomic feature
* and no ack response expected. Sender contract has no need to
* implement ack processing interfaces for this type requests.
*/
NONE_ATOMIC((byte) 0),

/**
* {@code ATOMIC_REQUEST} means this sdp packet is cross-chain sending to
* another blockchain which expected to receive the message contained in
* packet payload. This request expect an ack response from receiving
* blockchain to notify the sender contract that cross-chain calling success
* or not.
*/
ATOMIC_REQUEST((byte) 1),

/**
* {@code ACK_SUCCESS} means this sdp packet has been processed
* successfully on receiving blockchain and send an ack response back.
*/
ACK_SUCCESS((byte) 2),

/**
* {@code ACK_ERROR} means this sdp packet has been processed
* with errors when calling receiver contract on receiving blockchain.
* But there is no transaction revert on receiving blockchain and all
* state changes about cross-chain system contracts saved, for example
* sequence added. And then an ack response sent back.
*/
ACK_ERROR((byte) 3),

/**
* <p>
* {@code ACK_RECEIVE_TX_FAILED} means that sdp packet has been processed
* with errors and receiving transaction has been reverted. This is usually
* caused by bugs of cross-chain system contract implementation or receiving
* blockchain account.
* </p>
* <p>
* This type ack response wouldn't protect by ledger verification executed and signed by
* {@code PTC} because that no state update on receiving blockchain with transaction revert.
* Relayer would commit this ack response by a special {@code BBCService} method.
* So sender contract's developer must know this ack response is unsafe.
* </p>
*/
ACK_RECEIVE_TX_FAILED((byte) 4),

/**
* <p>
* {@code ACK_UNKNOWN_EXCEPTION} means that some unexpected situations happened
* like retry out of times or some timeout stuff.
* </p>
* <p>
* This type ack response wouldn't protect by ledger verification executed and signed by
* {@code PTC} because that no state update on receiving blockchain.
* Relayer would commit this ack response by a special {@code BBCService} method.
* So sender contract's developer must know this ack response is unsafe.
* </p>
*/
ACK_UNKNOWN_EXCEPTION((byte) 5);

public static AtomicFlagEnum parseFrom(byte value) {
if (value == NONE_ATOMIC.value) {
return NONE_ATOMIC;
} else if (value == ATOMIC_REQUEST.value) {
return ATOMIC_REQUEST;
} else if (value == ACK_SUCCESS.value) {
return ACK_SUCCESS;
} else if (value == ACK_ERROR.value) {
return ACK_ERROR;
} else if (value == ACK_RECEIVE_TX_FAILED.value) {
return ACK_RECEIVE_TX_FAILED;
} else if (value == ACK_UNKNOWN_EXCEPTION.value) {
return ACK_UNKNOWN_EXCEPTION;
}
throw new AntChainBridgeCommonsException(
CommonsErrorCodeEnum.SDP_MESSAGE_DECODE_ERROR,
"no sdp atomic flag found for " + ByteUtil.byteToUnsignedInt(value)
);
}

public static boolean withErrorMsg(AtomicFlagEnum atomicFlag) {
return ObjectUtil.isNotNull(atomicFlag) && atomicFlag.value > ACK_SUCCESS.value;
}

AtomicFlagEnum(byte value) {
this.value = value;
}

public boolean isAtomic() {
return this == ATOMIC_REQUEST;
}

private final byte value;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,118 @@
import com.alipay.antchain.bridge.commons.core.base.CrossChainIdentity;
import com.alipay.antchain.bridge.commons.core.base.IMessage;

/**
* Interface {@code ISDPMessage} defines all methods for the SDP
* message object.
*
* <p>
* Smart-contract Datagram Protocol, SDP in short, provides the
* crosschain communication ability between contracts on different
* blockchains. The SDP contract is supposed to pre-deployed on each
* blockchain involved in crosschain network. During the communication
* processing, SDP contracts pack the message from sender contract into
* SDP packet and sink the raw packet bytes into AM packet. After
* ACB network relaying the cross-chain message onto receiving blockchain,
* the SDP contract on receiving blockchain would unpack the SDP packet
* and deliver the message from sender contract to the identified
* receiver contract.
* </p>
* <p>
* SDP now provides two versions of implementations, version one and two.
* Version one provides ability to sending ordered or unordered messages
* to another contract. And version two offer the atomic type message sending
* to another contract expecting multiple type acknowledge responses
* in different situations. And version two is good at preventing replay attacks.
* </p>
*/
public interface ISDPMessage extends IMessage {

/**
* Get the receiving blockchain domain name.
*
* @return receiving blockchain domain name
*/
CrossChainDomain getTargetDomain();

/**
* Get the receiving contract identity.
*
* <p>
* All crosschain identity in AntChain Bridge crosschain network is 32 bytes
* fixed. Usually crosschain identity is hash value of 256 bit length or less
* bytes value with padding zeros as prefix.
* </p>
* @return crosschain identity
*/
CrossChainIdentity getTargetIdentity();

/**
* Return the sequence value in SDP packet.
* <p>
* If sequence greater than or equal to zero, it means ordered SDP packet.
* Ordered SDP packet would be committed to receiving blockchain by order.
* If the SDP packet with last sequence number is not committed on receiving
* blockchain, the next SDP packet can't be delivered successfully to receiving
* blockchain.
* </p>
* <p>
* If sequence is {@code 0xFFFFFFFF}, it means unordered SDP packet.
* Unordered SDP packet is parallel sent to receiving blockchain.
* </p>
*
* @return the sequence value in SDP packet
*/
int getSequence();

/**
* The message bytes from sender contract.
*
* @return raw message
*/
byte[] getPayload();

/**
* Version number of this SDP packet.
*
* @return version
*/
int getVersion();

/**
* Return the message id represents the sdp packet
* @return
*/
SDPMessageId getMessageId();

/**
* The nonce value for unordered packet.
*
* <p>
* In crosschain channel between sender and receiver, the nonce of each SDP
* packet is unique. The receiving SDP contract would check if the SDP packet
* has been processed by recording its nonce value.
* </p>
*
* <p>
* Only version two has this work.
* </p>
*
* @return nonce value
*/
long getNonce();

/**
* Shows that is this SDP packet atomic.
*
* @return atomic or not
*/
boolean getAtomic();

/**
* Method {@code getAtomicFlag} return the flag value shows that
* which atomic type of this sdp packet, details please check
* {@link AtomicFlagEnum}
* @return flag value to show the type
*/
AtomicFlagEnum getAtomicFlag();
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,37 @@ public static ISDPMessage createSDPMessage(byte[] rawMessage) {
return sdpMessage;
}

public static ISDPMessage createSDPMessage(int version, String targetDomain, byte[] targetIdentity, int sequence, byte[] payload) {
public static ISDPMessage createSDPMessage(int version, byte[] messageId, String targetDomain, byte[] targetIdentity, int sequence, byte[] payload) {
return createSDPMessage(version, messageId, targetDomain, targetIdentity, AtomicFlagEnum.NONE_ATOMIC, -1, sequence, payload, null);
}

public static ISDPMessage createSDPMessage(
int version,
byte[] messageId,
String targetDomain,
byte[] targetIdentity,
AtomicFlagEnum atomicFlag,
long nonce,
int sequence,
byte[] payload,
String errorMsg
) {
AbstractSDPMessage sdpMessage = createAbstractSDPMessage(version);

sdpMessage.setTargetDomain(new CrossChainDomain(targetDomain));
sdpMessage.setTargetIdentity(new CrossChainIdentity(targetIdentity));
sdpMessage.setSequence(sequence);
sdpMessage.setPayload(payload);

if (version == SDPMessageV2.MY_VERSION) {
((SDPMessageV2) sdpMessage).setMessageId(new SDPMessageId(messageId));
((SDPMessageV2) sdpMessage).setNonce(nonce);
((SDPMessageV2) sdpMessage).setAtomicFlag(atomicFlag);
if (AtomicFlagEnum.withErrorMsg(atomicFlag)) {
((SDPMessageV2) sdpMessage).setErrorMsg(errorMsg);
}
}

return sdpMessage;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.alipay.antchain.bridge.commons.core.sdp;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alipay.antchain.bridge.commons.exception.AntChainBridgeCommonsException;
import com.alipay.antchain.bridge.commons.exception.CommonsErrorCodeEnum;
import lombok.NonNull;
import lombok.Setter;

@Setter
public class SDPMessageId {

public static final SDPMessageId ZERO_MESSAGE_ID = new SDPMessageId(new byte[32]);

public SDPMessageId(@NonNull String messageIdHex) {
this(HexUtil.decodeHex(messageIdHex));
}

public SDPMessageId(byte[] messageId) {
if (ObjectUtil.isNull(messageId)) {
throw new AntChainBridgeCommonsException(
CommonsErrorCodeEnum.SDP_MESSAGE_DECODE_ERROR,
"message id is null"
);
}
if (messageId.length != 32) {
throw new AntChainBridgeCommonsException(
CommonsErrorCodeEnum.SDP_MESSAGE_DECODE_ERROR,
StrUtil.format("expected 32 bytes but get {}", messageId.length)
);
}
this.messageId = messageId;
}

private byte[] messageId;

public String toHexStr() {
return HexUtil.encodeHexStr(this.messageId);
}

public byte[] toByte32() {
return messageId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,34 @@ public void setPayload(byte[] payload) {
public boolean getAtomic() {
return false;
}

@Override
public AtomicFlagEnum getAtomicFlag() {
return AtomicFlagEnum.NONE_ATOMIC;
}

@Override
public long getNonce() {
return -1;
}

@Override
public SDPMessageId getMessageId() {
return SDPMessageId.ZERO_MESSAGE_ID;
}

@Override
public void setNonce(long nonce) {

}

@Override
public void setAtomicFlag(AtomicFlagEnum atomicFlag) {

}

@Override
public void setMessageId(SDPMessageId messageId) {

}
}
Loading

0 comments on commit 785a5c2

Please sign in to comment.