Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
7ee8d8d3
Unverified
Commit
7ee8d8d3
authored
Jan 19, 2022
by
kf
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: implement getMessageStatus
parent
f8531d88
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
510 additions
and
41 deletions
+510
-41
cross-chain-provider.ts
packages/sdk/src/cross-chain-provider.ts
+209
-1
cross-chain-provider.ts
packages/sdk/src/interfaces/cross-chain-provider.ts
+61
-1
types.ts
packages/sdk/src/interfaces/types.ts
+11
-1
MockSCC.sol
packages/sdk/test/contracts/MockSCC.sol
+48
-0
cross-chain-provider.spec.ts
packages/sdk/test/cross-chain-provider.spec.ts
+173
-38
constants.ts
packages/sdk/test/helpers/constants.ts
+7
-0
index.ts
packages/sdk/test/helpers/index.ts
+1
-0
No files found.
packages/sdk/src/cross-chain-provider.ts
View file @
7ee8d8d3
...
@@ -23,6 +23,8 @@ import {
...
@@ -23,6 +23,8 @@ import {
MessageReceiptStatus
,
MessageReceiptStatus
,
CustomBridges
,
CustomBridges
,
CustomBridgesLike
,
CustomBridgesLike
,
StateRoot
,
StateRootBatch
,
}
from
'
./interfaces
'
}
from
'
./interfaces
'
import
{
import
{
toProvider
,
toProvider
,
...
@@ -38,6 +40,7 @@ export class CrossChainProvider implements ICrossChainProvider {
...
@@ -38,6 +40,7 @@ export class CrossChainProvider implements ICrossChainProvider {
public
l1Provider
:
Provider
public
l1Provider
:
Provider
public
l2Provider
:
Provider
public
l2Provider
:
Provider
public
l1ChainId
:
number
public
l1ChainId
:
number
public
l1BlockTime
:
number
public
contracts
:
OEContracts
public
contracts
:
OEContracts
public
bridges
:
CustomBridges
public
bridges
:
CustomBridges
...
@@ -48,18 +51,24 @@ export class CrossChainProvider implements ICrossChainProvider {
...
@@ -48,18 +51,24 @@ export class CrossChainProvider implements ICrossChainProvider {
* @param opts.l1Provider Provider for the L1 chain, or a JSON-RPC url.
* @param opts.l1Provider Provider for the L1 chain, or a JSON-RPC url.
* @param opts.l2Provider Provider for the L2 chain, or a JSON-RPC url.
* @param opts.l2Provider Provider for the L2 chain, or a JSON-RPC url.
* @param opts.l1ChainId Chain ID for the L1 chain.
* @param opts.l1ChainId Chain ID for the L1 chain.
* @param opts.l1BlockTime Optional L1 block time in seconds. Defaults to 15 seconds.
* @param opts.contracts Optional contract address overrides.
* @param opts.contracts Optional contract address overrides.
* @param opts.bridges Optional bridge address list.
*/
*/
constructor
(
opts
:
{
constructor
(
opts
:
{
l1Provider
:
ProviderLike
l1Provider
:
ProviderLike
l2Provider
:
ProviderLike
l2Provider
:
ProviderLike
l1ChainId
:
NumberLike
l1ChainId
:
NumberLike
l1BlockTime
?:
NumberLike
contracts
?:
DeepPartial
<
OEContractsLike
>
contracts
?:
DeepPartial
<
OEContractsLike
>
bridges
?:
Partial
<
CustomBridgesLike
>
bridges
?:
Partial
<
CustomBridgesLike
>
})
{
})
{
this
.
l1Provider
=
toProvider
(
opts
.
l1Provider
)
this
.
l1Provider
=
toProvider
(
opts
.
l1Provider
)
this
.
l2Provider
=
toProvider
(
opts
.
l2Provider
)
this
.
l2Provider
=
toProvider
(
opts
.
l2Provider
)
this
.
l1ChainId
=
toBigNumber
(
opts
.
l1ChainId
).
toNumber
()
this
.
l1ChainId
=
toBigNumber
(
opts
.
l1ChainId
).
toNumber
()
this
.
l1BlockTime
=
opts
.
l1BlockTime
?
toBigNumber
(
opts
.
l1ChainId
).
toNumber
()
:
15
this
.
contracts
=
getAllOEContracts
(
this
.
l1ChainId
,
{
this
.
contracts
=
getAllOEContracts
(
this
.
l1ChainId
,
{
l1SignerOrProvider
:
this
.
l1Provider
,
l1SignerOrProvider
:
this
.
l1Provider
,
l2SignerOrProvider
:
this
.
l2Provider
,
l2SignerOrProvider
:
this
.
l2Provider
,
...
@@ -335,7 +344,41 @@ export class CrossChainProvider implements ICrossChainProvider {
...
@@ -335,7 +344,41 @@ export class CrossChainProvider implements ICrossChainProvider {
}
}
public
async
getMessageStatus
(
message
:
MessageLike
):
Promise
<
MessageStatus
>
{
public
async
getMessageStatus
(
message
:
MessageLike
):
Promise
<
MessageStatus
>
{
throw
new
Error
(
'
Not implemented
'
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
receipt
=
await
this
.
getMessageReceipt
(
resolved
)
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
receipt
===
null
)
{
return
MessageStatus
.
UNCONFIRMED_L1_TO_L2_MESSAGE
}
else
{
if
(
receipt
.
receiptStatus
===
MessageReceiptStatus
.
RELAYED_SUCCEEDED
)
{
return
MessageStatus
.
RELAYED
}
else
{
return
MessageStatus
.
FAILED_L1_TO_L2_MESSAGE
}
}
}
else
{
if
(
receipt
===
null
)
{
const
stateRoot
=
await
this
.
getMessageStateRoot
(
resolved
)
if
(
stateRoot
===
null
)
{
return
MessageStatus
.
STATE_ROOT_NOT_PUBLISHED
}
else
{
const
challengePeriod
=
await
this
.
getChallengePeriodBlocks
()
const
latestBlock
=
await
this
.
l1Provider
.
getBlockNumber
()
if
(
stateRoot
.
blockNumber
+
challengePeriod
>
latestBlock
)
{
return
MessageStatus
.
IN_CHALLENGE_PERIOD
}
else
{
return
MessageStatus
.
READY_FOR_RELAY
}
}
}
else
{
if
(
receipt
.
receiptStatus
===
MessageReceiptStatus
.
RELAYED_SUCCEEDED
)
{
return
MessageStatus
.
RELAYED
}
else
{
return
MessageStatus
.
READY_FOR_RELAY
}
}
}
}
}
public
async
getMessageReceipt
(
public
async
getMessageReceipt
(
...
@@ -436,4 +479,169 @@ export class CrossChainProvider implements ICrossChainProvider {
...
@@ -436,4 +479,169 @@ export class CrossChainProvider implements ICrossChainProvider {
):
Promise
<
number
>
{
):
Promise
<
number
>
{
throw
new
Error
(
'
Not implemented
'
)
throw
new
Error
(
'
Not implemented
'
)
}
}
public
async
getChallengePeriodSeconds
():
Promise
<
number
>
{
const
challengePeriod
=
await
this
.
contracts
.
l1
.
StateCommitmentChain
.
FRAUD_PROOF_WINDOW
()
return
challengePeriod
.
toNumber
()
}
public
async
getChallengePeriodBlocks
():
Promise
<
number
>
{
return
Math
.
ceil
(
(
await
this
.
getChallengePeriodSeconds
())
/
this
.
l1BlockTime
)
}
public
async
getMessageStateRoot
(
message
:
MessageLike
):
Promise
<
StateRoot
|
null
>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
// State roots are only a thing for L2 to L1 messages.
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
throw
new
Error
(
`cannot get a state root for an L1 to L2 message`
)
}
// We need the block number of the transaction that triggered the message so we can look up the
// state root batch that corresponds to that block number.
const
messageTxReceipt
=
await
this
.
l2Provider
.
getTransactionReceipt
(
resolved
.
transactionHash
)
// Every block has exactly one transaction in it. Since there's a genesis block, the
// transaction index will always be one less than the block number.
const
messageTxIndex
=
messageTxReceipt
.
blockNumber
-
1
// Pull down the state root batch, we'll try to pick out the specific state root that
// corresponds to our message.
const
stateRootBatch
=
await
this
.
getStateRootBatchByTransactionIndex
(
messageTxIndex
)
// No state root batch, no state root.
if
(
stateRootBatch
===
null
)
{
return
null
}
// We have a state root batch, now we need to find the specific state root for our transaction.
// First we need to figure out the index of the state root within the batch we found. This is
// going to be the original transaction index offset by the total number of previous state
// roots.
const
indexInBatch
=
messageTxIndex
-
stateRootBatch
.
header
.
prevTotalElements
.
toNumber
()
// Just a sanity check.
if
(
stateRootBatch
.
stateRoots
.
length
<=
indexInBatch
)
{
// Should never happen!
throw
new
Error
(
`state root does not exist in batch`
)
}
return
{
blockNumber
:
stateRootBatch
.
blockNumber
,
header
:
stateRootBatch
.
header
,
stateRoot
:
stateRootBatch
.
stateRoots
[
indexInBatch
],
}
}
public
async
getStateBatchAppendedEventByBatchIndex
(
batchIndex
:
number
):
Promise
<
ethers
.
Event
|
null
>
{
const
events
=
await
this
.
contracts
.
l1
.
StateCommitmentChain
.
queryFilter
(
this
.
contracts
.
l1
.
StateCommitmentChain
.
filters
.
StateBatchAppended
(
batchIndex
)
)
if
(
events
.
length
===
0
)
{
return
null
}
else
if
(
events
.
length
>
1
)
{
// Should never happen!
throw
new
Error
(
`found more than one StateBatchAppended event`
)
}
else
{
return
events
[
0
]
}
}
public
async
getStateBatchAppendedEventByTransactionIndex
(
transactionIndex
:
number
):
Promise
<
ethers
.
Event
|
null
>
{
const
isEventHi
=
(
event
:
ethers
.
Event
,
index
:
number
)
=>
{
const
prevTotalElements
=
event
.
args
.
_prevTotalElements
.
toNumber
()
return
index
<
prevTotalElements
}
const
isEventLo
=
(
event
:
ethers
.
Event
,
index
:
number
)
=>
{
const
prevTotalElements
=
event
.
args
.
_prevTotalElements
.
toNumber
()
const
batchSize
=
event
.
args
.
_batchSize
.
toNumber
()
return
index
>=
prevTotalElements
+
batchSize
}
const
totalBatches
:
ethers
.
BigNumber
=
await
this
.
contracts
.
l1
.
StateCommitmentChain
.
getTotalBatches
()
if
(
totalBatches
.
eq
(
0
))
{
return
null
}
let
lowerBound
=
0
let
upperBound
=
totalBatches
.
toNumber
()
-
1
let
batchEvent
:
ethers
.
Event
|
null
=
await
this
.
getStateBatchAppendedEventByBatchIndex
(
upperBound
)
if
(
isEventLo
(
batchEvent
,
transactionIndex
))
{
// Upper bound is too low, means this transaction doesn't have a corresponding state batch yet.
return
null
}
else
if
(
!
isEventHi
(
batchEvent
,
transactionIndex
))
{
// Upper bound is not too low and also not too high. This means the upper bound event is the
// one we're looking for! Return it.
return
batchEvent
}
// Binary search to find the right event. The above checks will guarantee that the event does
// exist and that we'll find it during this search.
while
(
lowerBound
<
upperBound
)
{
const
middleOfBounds
=
Math
.
floor
((
lowerBound
+
upperBound
)
/
2
)
batchEvent
=
await
this
.
getStateBatchAppendedEventByBatchIndex
(
middleOfBounds
)
if
(
isEventHi
(
batchEvent
,
transactionIndex
))
{
upperBound
=
middleOfBounds
}
else
if
(
isEventLo
(
batchEvent
,
transactionIndex
))
{
lowerBound
=
middleOfBounds
}
else
{
break
}
}
return
batchEvent
}
public
async
getStateRootBatchByTransactionIndex
(
transactionIndex
:
number
):
Promise
<
StateRootBatch
|
null
>
{
const
stateBatchAppendedEvent
=
await
this
.
getStateBatchAppendedEventByTransactionIndex
(
transactionIndex
)
if
(
stateBatchAppendedEvent
===
null
)
{
return
null
}
const
stateBatchTransaction
=
await
stateBatchAppendedEvent
.
getTransaction
()
const
[
stateRoots
]
=
this
.
contracts
.
l1
.
StateCommitmentChain
.
interface
.
decodeFunctionData
(
'
appendStateBatch
'
,
stateBatchTransaction
.
data
)
return
{
blockNumber
:
stateBatchAppendedEvent
.
blockNumber
,
stateRoots
,
header
:
{
batchIndex
:
stateBatchAppendedEvent
.
args
.
_batchIndex
,
batchRoot
:
stateBatchAppendedEvent
.
args
.
_batchRoot
,
batchSize
:
stateBatchAppendedEvent
.
args
.
_batchSize
,
prevTotalElements
:
stateBatchAppendedEvent
.
args
.
_prevTotalElements
,
extraData
:
stateBatchAppendedEvent
.
args
.
_extraData
,
},
}
}
}
}
packages/sdk/src/interfaces/cross-chain-provider.ts
View file @
7ee8d8d3
import
{
BigNumber
}
from
'
ethers
'
import
{
Event
,
BigNumber
}
from
'
ethers
'
import
{
Provider
,
BlockTag
}
from
'
@ethersproject/abstract-provider
'
import
{
Provider
,
BlockTag
}
from
'
@ethersproject/abstract-provider
'
import
{
import
{
MessageLike
,
MessageLike
,
...
@@ -12,6 +12,8 @@ import {
...
@@ -12,6 +12,8 @@ import {
OEContracts
,
OEContracts
,
MessageReceipt
,
MessageReceipt
,
CustomBridges
,
CustomBridges
,
StateRoot
,
StateRootBatch
,
}
from
'
./types
'
}
from
'
./types
'
/**
/**
...
@@ -225,4 +227,62 @@ export interface ICrossChainProvider {
...
@@ -225,4 +227,62 @@ export interface ICrossChainProvider {
* @returns Estimated amount of time remaining (in blocks) before the message can be executed.
* @returns Estimated amount of time remaining (in blocks) before the message can be executed.
*/
*/
estimateMessageWaitTimeBlocks
(
message
:
MessageLike
):
Promise
<
number
>
estimateMessageWaitTimeBlocks
(
message
:
MessageLike
):
Promise
<
number
>
/**
* Queries the current challenge period in seconds from the StateCommitmentChain.
*
* @returns Current challenge period in seconds.
*/
getChallengePeriodSeconds
():
Promise
<
number
>
/**
* Queries the current challenge period in blocks from the StateCommitmentChain. Estimation is
* based on the challenge period in seconds divided by the L1 block time.
*
* @returns Current challenge period in blocks.
*/
getChallengePeriodBlocks
():
Promise
<
number
>
/**
* Returns the state root that corresponds to a given message. This is the state root for the
* block in which the transaction was included, as published to the StateCommitmentChain. If the
* state root for the given message has not been published yet, this function returns null.
*
* @param message Message to find a state root for.
* @returns State root for the block in which the message was created.
*/
getMessageStateRoot
(
message
:
MessageLike
):
Promise
<
StateRoot
|
null
>
/**
* Returns the StateBatchAppended event that was emitted when the batch with a given index was
* created. Returns null if no such event exists (the batch has not been submitted).
*
* @param batchIndex Index of the batch to find an event for.
* @returns StateBatchAppended event for the batch, or null if no such batch exists.
*/
getStateBatchAppendedEventByBatchIndex
(
batchIndex
:
number
):
Promise
<
Event
|
null
>
/**
* Returns the StateBatchAppended event for the batch that includes the transaction with the
* given index. Returns null if no such event exists.
*
* @param transactionIndex Index of the L2 transaction to find an event for.
* @returns StateBatchAppended event for the batch that includes the given transaction by index.
*/
getStateBatchAppendedEventByTransactionIndex
(
transactionIndex
:
number
):
Promise
<
Event
|
null
>
/**
* Returns information about the state root batch that included the state root for the given
* transaction by index. Returns null if no such state root has been published yet.
*
* @param transactionIndex Index of the L2 transaction to find a state root batch for.
* @returns State root batch for the given transaction index, or null if none exists yet.
*/
getStateRootBatchByTransactionIndex
(
transactionIndex
:
number
):
Promise
<
StateRootBatch
|
null
>
}
}
packages/sdk/src/interfaces/types.ts
View file @
7ee8d8d3
...
@@ -212,9 +212,19 @@ export interface StateRootBatchHeader {
...
@@ -212,9 +212,19 @@ export interface StateRootBatchHeader {
}
}
/**
/**
* State root batch, including header and actual state roots.
* Information about a state root, including header, block number, and root iself.
*/
export
interface
StateRoot
{
blockNumber
:
number
header
:
StateRootBatchHeader
stateRoot
:
string
}
/**
* Information about a batch of state roots.
*/
*/
export
interface
StateRootBatch
{
export
interface
StateRootBatch
{
blockNumber
:
number
header
:
StateRootBatchHeader
header
:
StateRootBatchHeader
stateRoots
:
string
[]
stateRoots
:
string
[]
}
}
...
...
packages/sdk/test/contracts/MockSCC.sol
0 → 100644
View file @
7ee8d8d3
pragma solidity ^0.8.9;
contract MockSCC {
event StateBatchAppended(
uint256 indexed _batchIndex,
bytes32 _batchRoot,
uint256 _batchSize,
uint256 _prevTotalElements,
bytes _extraData
);
struct StateBatchAppendedArgs {
uint256 batchIndex;
bytes32 batchRoot;
uint256 batchSize;
uint256 prevTotalElements;
bytes extraData;
}
// Window in seconds, will resolve to 100 blocks.
uint256 public FRAUD_PROOF_WINDOW = 1500;
uint256 public batches = 0;
StateBatchAppendedArgs public sbaParams;
function getTotalBatches() public view returns (uint256) {
return batches;
}
function setSBAParams(
StateBatchAppendedArgs memory _args
) public {
sbaParams = _args;
}
function appendStateBatch(
bytes32[] memory _roots,
uint256 _shouldStartAtIndex
) public {
batches++;
emit StateBatchAppended(
sbaParams.batchIndex,
sbaParams.batchRoot,
sbaParams.batchSize,
sbaParams.prevTotalElements,
sbaParams.extraData
);
}
}
packages/sdk/test/cross-chain-provider.spec.ts
View file @
7ee8d8d3
...
@@ -8,7 +8,10 @@ import {
...
@@ -8,7 +8,10 @@ import {
CONTRACT_ADDRESSES
,
CONTRACT_ADDRESSES
,
hashCrossChainMessage
,
hashCrossChainMessage
,
omit
,
omit
,
MessageStatus
,
CrossChainMessage
,
}
from
'
../src
'
}
from
'
../src
'
import
{
DUMMY_MESSAGE
}
from
'
./helpers
'
describe
(
'
CrossChainProvider
'
,
()
=>
{
describe
(
'
CrossChainProvider
'
,
()
=>
{
describe
(
'
construction
'
,
()
=>
{
describe
(
'
construction
'
,
()
=>
{
...
@@ -250,13 +253,7 @@ describe('CrossChainProvider', () => {
...
@@ -250,13 +253,7 @@ describe('CrossChainProvider', () => {
for
(
const
n
of
[
1
,
2
,
4
,
8
])
{
for
(
const
n
of
[
1
,
2
,
4
,
8
])
{
it
(
`should find
${
n
}
messages when the transaction emits
${
n
}
messages`
,
async
()
=>
{
it
(
`should find
${
n
}
messages when the transaction emits
${
n
}
messages`
,
async
()
=>
{
const
messages
=
[...
Array
(
n
)].
map
(()
=>
{
const
messages
=
[...
Array
(
n
)].
map
(()
=>
{
return
{
return
DUMMY_MESSAGE
target
:
'
0x
'
+
'
11
'
.
repeat
(
20
),
sender
:
'
0x
'
+
'
22
'
.
repeat
(
20
),
message
:
'
0x
'
+
'
33
'
.
repeat
(
64
),
messageNonce
:
1234
,
gasLimit
:
100000
,
}
})
})
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
(
messages
)
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
(
messages
)
...
@@ -309,13 +306,7 @@ describe('CrossChainProvider', () => {
...
@@ -309,13 +306,7 @@ describe('CrossChainProvider', () => {
for
(
const
n
of
[
1
,
2
,
4
,
8
])
{
for
(
const
n
of
[
1
,
2
,
4
,
8
])
{
it
(
`should find
${
n
}
messages when the transaction emits
${
n
}
messages`
,
async
()
=>
{
it
(
`should find
${
n
}
messages when the transaction emits
${
n
}
messages`
,
async
()
=>
{
const
messages
=
[...
Array
(
n
)].
map
(()
=>
{
const
messages
=
[...
Array
(
n
)].
map
(()
=>
{
return
{
return
DUMMY_MESSAGE
target
:
'
0x
'
+
'
11
'
.
repeat
(
20
),
sender
:
'
0x
'
+
'
22
'
.
repeat
(
20
),
message
:
'
0x
'
+
'
33
'
.
repeat
(
64
),
messageNonce
:
1234
,
gasLimit
:
100000
,
}
})
})
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
(
messages
)
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
(
messages
)
...
@@ -736,15 +727,7 @@ describe('CrossChainProvider', () => {
...
@@ -736,15 +727,7 @@ describe('CrossChainProvider', () => {
describe
(
'
when the input is a TransactionLike
'
,
()
=>
{
describe
(
'
when the input is a TransactionLike
'
,
()
=>
{
describe
(
'
when the transaction sent exactly one message
'
,
()
=>
{
describe
(
'
when the transaction sent exactly one message
'
,
()
=>
{
it
(
'
should return the CrossChainMessage sent in the transaction
'
,
async
()
=>
{
it
(
'
should return the CrossChainMessage sent in the transaction
'
,
async
()
=>
{
const
message
=
{
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
([
DUMMY_MESSAGE
])
target
:
'
0x
'
+
'
11
'
.
repeat
(
20
),
sender
:
'
0x
'
+
'
22
'
.
repeat
(
20
),
message
:
'
0x
'
+
'
33
'
.
repeat
(
64
),
messageNonce
:
1234
,
gasLimit
:
100000
,
}
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
([
message
])
const
foundCrossChainMessages
=
const
foundCrossChainMessages
=
await
provider
.
getMessagesByTransaction
(
tx
)
await
provider
.
getMessagesByTransaction
(
tx
)
const
resolved
=
await
provider
.
toCrossChainMessage
(
tx
)
const
resolved
=
await
provider
.
toCrossChainMessage
(
tx
)
...
@@ -755,13 +738,7 @@ describe('CrossChainProvider', () => {
...
@@ -755,13 +738,7 @@ describe('CrossChainProvider', () => {
describe
(
'
when the transaction sent more than one message
'
,
()
=>
{
describe
(
'
when the transaction sent more than one message
'
,
()
=>
{
it
(
'
should throw an error
'
,
async
()
=>
{
it
(
'
should throw an error
'
,
async
()
=>
{
const
messages
=
[...
Array
(
2
)].
map
(()
=>
{
const
messages
=
[...
Array
(
2
)].
map
(()
=>
{
return
{
return
DUMMY_MESSAGE
target
:
'
0x
'
+
'
11
'
.
repeat
(
20
),
sender
:
'
0x
'
+
'
22
'
.
repeat
(
20
),
message
:
'
0x
'
+
'
33
'
.
repeat
(
64
),
messageNonce
:
1234
,
gasLimit
:
100000
,
}
})
})
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
(
messages
)
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
(
messages
)
...
@@ -783,45 +760,203 @@ describe('CrossChainProvider', () => {
...
@@ -783,45 +760,203 @@ describe('CrossChainProvider', () => {
})
})
describe
(
'
getMessageStatus
'
,
()
=>
{
describe
(
'
getMessageStatus
'
,
()
=>
{
let
scc
:
Contract
let
l1Messenger
:
Contract
let
l2Messenger
:
Contract
let
provider
:
CrossChainProvider
beforeEach
(
async
()
=>
{
// TODO: Get rid of the nested awaits here. Could be a good first issue for someone.
scc
=
(
await
(
await
ethers
.
getContractFactory
(
'
MockSCC
'
)).
deploy
())
as
any
l1Messenger
=
(
await
(
await
ethers
.
getContractFactory
(
'
MockMessenger
'
)
).
deploy
())
as
any
l2Messenger
=
(
await
(
await
ethers
.
getContractFactory
(
'
MockMessenger
'
)
).
deploy
())
as
any
provider
=
new
CrossChainProvider
({
l1Provider
:
ethers
.
provider
,
l2Provider
:
ethers
.
provider
,
l1ChainId
:
31337
,
contracts
:
{
l1
:
{
L1CrossDomainMessenger
:
l1Messenger
.
address
,
StateCommitmentChain
:
scc
.
address
,
},
l2
:
{
L2CrossDomainMessenger
:
l2Messenger
.
address
,
},
},
})
})
const
sendAndGetDummyMessage
=
async
(
direction
:
MessageDirection
)
=>
{
const
messenger
=
direction
===
MessageDirection
.
L1_TO_L2
?
l1Messenger
:
l2Messenger
const
tx
=
await
messenger
.
triggerSentMessageEvents
([
DUMMY_MESSAGE
])
return
(
await
provider
.
getMessagesByTransaction
(
tx
,
{
direction
,
})
)[
0
]
}
const
submitStateRootBatchForMessage
=
async
(
message
:
CrossChainMessage
)
=>
{
await
scc
.
setSBAParams
({
batchIndex
:
0
,
batchRoot
:
ethers
.
constants
.
HashZero
,
batchSize
:
1
,
prevTotalElements
:
message
.
blockNumber
,
extraData
:
'
0x
'
,
})
await
scc
.
appendStateBatch
([
ethers
.
constants
.
HashZero
],
0
)
}
describe
(
'
when the message is an L1 => L2 message
'
,
()
=>
{
describe
(
'
when the message is an L1 => L2 message
'
,
()
=>
{
describe
(
'
when the message has not been executed on L2 yet
'
,
()
=>
{
describe
(
'
when the message has not been executed on L2 yet
'
,
()
=>
{
it
(
'
should return a status of UNCONFIRMED_L1_TO_L2_MESSAGE
'
)
it
(
'
should return a status of UNCONFIRMED_L1_TO_L2_MESSAGE
'
,
async
()
=>
{
const
message
=
await
sendAndGetDummyMessage
(
MessageDirection
.
L1_TO_L2
)
expect
(
await
provider
.
getMessageStatus
(
message
)).
to
.
equal
(
MessageStatus
.
UNCONFIRMED_L1_TO_L2_MESSAGE
)
})
})
})
describe
(
'
when the message has been executed on L2
'
,
()
=>
{
describe
(
'
when the message has been executed on L2
'
,
()
=>
{
it
(
'
should return a status of RELAYED
'
)
it
(
'
should return a status of RELAYED
'
,
async
()
=>
{
const
message
=
await
sendAndGetDummyMessage
(
MessageDirection
.
L1_TO_L2
)
await
l2Messenger
.
triggerRelayedMessageEvents
([
hashCrossChainMessage
(
message
),
])
expect
(
await
provider
.
getMessageStatus
(
message
)).
to
.
equal
(
MessageStatus
.
RELAYED
)
})
})
})
describe
(
'
when the message has been executed but failed
'
,
()
=>
{
describe
(
'
when the message has been executed but failed
'
,
()
=>
{
it
(
'
should return a status of FAILED_L1_TO_L2_MESSAGE
'
)
it
(
'
should return a status of FAILED_L1_TO_L2_MESSAGE
'
,
async
()
=>
{
const
message
=
await
sendAndGetDummyMessage
(
MessageDirection
.
L1_TO_L2
)
await
l2Messenger
.
triggerFailedRelayedMessageEvents
([
hashCrossChainMessage
(
message
),
])
expect
(
await
provider
.
getMessageStatus
(
message
)).
to
.
equal
(
MessageStatus
.
FAILED_L1_TO_L2_MESSAGE
)
})
})
})
})
})
describe
(
'
when the message is an L2 => L1 message
'
,
()
=>
{
describe
(
'
when the message is an L2 => L1 message
'
,
()
=>
{
describe
(
'
when the message state root has not been published
'
,
()
=>
{
describe
(
'
when the message state root has not been published
'
,
()
=>
{
it
(
'
should return a status of STATE_ROOT_NOT_PUBLISHED
'
)
it
(
'
should return a status of STATE_ROOT_NOT_PUBLISHED
'
,
async
()
=>
{
const
message
=
await
sendAndGetDummyMessage
(
MessageDirection
.
L2_TO_L1
)
expect
(
await
provider
.
getMessageStatus
(
message
)).
to
.
equal
(
MessageStatus
.
STATE_ROOT_NOT_PUBLISHED
)
})
})
})
describe
(
'
when the message state root is still in the challenge period
'
,
()
=>
{
describe
(
'
when the message state root is still in the challenge period
'
,
()
=>
{
it
(
'
should return a status of IN_CHALLENGE_PERIOD
'
)
it
(
'
should return a status of IN_CHALLENGE_PERIOD
'
,
async
()
=>
{
const
message
=
await
sendAndGetDummyMessage
(
MessageDirection
.
L2_TO_L1
)
await
submitStateRootBatchForMessage
(
message
)
expect
(
await
provider
.
getMessageStatus
(
message
)).
to
.
equal
(
MessageStatus
.
IN_CHALLENGE_PERIOD
)
})
})
})
describe
(
'
when the message is no longer in the challenge period
'
,
()
=>
{
describe
(
'
when the message is no longer in the challenge period
'
,
()
=>
{
describe
(
'
when the message has been relayed successfully
'
,
()
=>
{
describe
(
'
when the message has been relayed successfully
'
,
()
=>
{
it
(
'
should return a status of RELAYED
'
)
it
(
'
should return a status of RELAYED
'
,
async
()
=>
{
const
message
=
await
sendAndGetDummyMessage
(
MessageDirection
.
L2_TO_L1
)
await
submitStateRootBatchForMessage
(
message
)
const
challengePeriod
=
await
provider
.
getChallengePeriodBlocks
()
for
(
let
x
=
0
;
x
<
challengePeriod
+
1
;
x
++
)
{
await
ethers
.
provider
.
send
(
'
evm_mine
'
,
[])
}
await
l1Messenger
.
triggerRelayedMessageEvents
([
hashCrossChainMessage
(
message
),
])
expect
(
await
provider
.
getMessageStatus
(
message
)).
to
.
equal
(
MessageStatus
.
RELAYED
)
})
})
})
describe
(
'
when the message has been relayed but the relay failed
'
,
()
=>
{
describe
(
'
when the message has been relayed but the relay failed
'
,
()
=>
{
it
(
'
should return a status of READY_FOR_RELAY
'
)
it
(
'
should return a status of READY_FOR_RELAY
'
,
async
()
=>
{
const
message
=
await
sendAndGetDummyMessage
(
MessageDirection
.
L2_TO_L1
)
await
submitStateRootBatchForMessage
(
message
)
const
challengePeriod
=
await
provider
.
getChallengePeriodBlocks
()
for
(
let
x
=
0
;
x
<
challengePeriod
+
1
;
x
++
)
{
await
ethers
.
provider
.
send
(
'
evm_mine
'
,
[])
}
await
l1Messenger
.
triggerFailedRelayedMessageEvents
([
hashCrossChainMessage
(
message
),
])
expect
(
await
provider
.
getMessageStatus
(
message
)).
to
.
equal
(
MessageStatus
.
READY_FOR_RELAY
)
})
})
})
describe
(
'
when the message has not been relayed
'
,
()
=>
{
describe
(
'
when the message has not been relayed
'
,
()
=>
{
it
(
'
should return a status of READY_FOR_RELAY
'
)
it
(
'
should return a status of READY_FOR_RELAY
'
,
async
()
=>
{
const
message
=
await
sendAndGetDummyMessage
(
MessageDirection
.
L2_TO_L1
)
await
submitStateRootBatchForMessage
(
message
)
const
challengePeriod
=
await
provider
.
getChallengePeriodBlocks
()
for
(
let
x
=
0
;
x
<
challengePeriod
+
1
;
x
++
)
{
await
ethers
.
provider
.
send
(
'
evm_mine
'
,
[])
}
expect
(
await
provider
.
getMessageStatus
(
message
)).
to
.
equal
(
MessageStatus
.
READY_FOR_RELAY
)
})
})
})
})
})
})
})
describe
(
'
when the message does not exist
'
,
()
=>
{
describe
(
'
when the message does not exist
'
,
()
=>
{
// TODO: Figure out if this is the correct behavior. Mark suggests perhaps returning null.
it
(
'
should throw an error
'
)
it
(
'
should throw an error
'
)
})
})
})
})
...
...
packages/sdk/test/helpers/constants.ts
0 → 100644
View file @
7ee8d8d3
export
const
DUMMY_MESSAGE
=
{
target
:
'
0x
'
+
'
11
'
.
repeat
(
20
),
sender
:
'
0x
'
+
'
22
'
.
repeat
(
20
),
message
:
'
0x
'
+
'
33
'
.
repeat
(
64
),
messageNonce
:
1234
,
gasLimit
:
100000
,
}
packages/sdk/test/helpers/index.ts
0 → 100644
View file @
7ee8d8d3
export
*
from
'
./constants
'
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment