Commit 01cffe2d authored by Maurelian's avatar Maurelian Committed by GitHub

Improving comments and some names (#211)

* Add missing interface function, and reorder funcs to match impl

* Replace '@inheritdoc' with actual docs

* Rename FraudContributor file with Abs prefix

* fix imports and interface visibility

* uncomment function to fix build process

* Update contracts/optimistic-ethereum/OVM/chain/OVM_CanonicalTransactionChain.sol
Co-authored-by: default avatarben-chain <ben@pseudonym.party>

* rename BaseCrossDomainManager to indicate abstract status

* fix return comment

* Add missing override kw
Co-authored-by: default avatarben-chain <ben@pseudonym.party>
parent 67c91869
...@@ -3,13 +3,13 @@ pragma solidity >0.5.0 <0.8.0; ...@@ -3,13 +3,13 @@ pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
/* Interface Imports */ /* Interface Imports */
import { iOVM_BaseCrossDomainMessenger } from "../../iOVM/bridge/iOVM_BaseCrossDomainMessenger.sol"; import { iAbs_BaseCrossDomainMessenger } from "../../iOVM/bridge/iAbs_BaseCrossDomainMessenger.sol";
/* Library Imports */ /* Library Imports */
import { Lib_ReentrancyGuard } from "../../libraries/utils/Lib_ReentrancyGuard.sol"; import { Lib_ReentrancyGuard } from "../../libraries/utils/Lib_ReentrancyGuard.sol";
/** /**
* @title OVM_BaseCrossDomainMessenger * @title Abs_BaseCrossDomainMessenger
* @dev The Base Cross Domain Messenger is an abstract contract providing the interface and common functionality used in the * @dev The Base Cross Domain Messenger is an abstract contract providing the interface and common functionality used in the
* L1 and L2 Cross Domain Messengers. It can also serve as a template for developers wishing to implement a custom bridge * L1 and L2 Cross Domain Messengers. It can also serve as a template for developers wishing to implement a custom bridge
* contract to suit their needs. * contract to suit their needs.
...@@ -17,7 +17,7 @@ import { Lib_ReentrancyGuard } from "../../libraries/utils/Lib_ReentrancyGuard.s ...@@ -17,7 +17,7 @@ import { Lib_ReentrancyGuard } from "../../libraries/utils/Lib_ReentrancyGuard.s
* Compiler used: defined by child contract * Compiler used: defined by child contract
* Runtime target: defined by child contract * Runtime target: defined by child contract
*/ */
abstract contract OVM_BaseCrossDomainMessenger is iOVM_BaseCrossDomainMessenger, Lib_ReentrancyGuard { abstract contract Abs_BaseCrossDomainMessenger is iAbs_BaseCrossDomainMessenger, Lib_ReentrancyGuard {
/********************** /**********************
* Contract Variables * * Contract Variables *
......
...@@ -15,7 +15,7 @@ import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalT ...@@ -15,7 +15,7 @@ import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalT
import { iOVM_StateCommitmentChain } from "../../iOVM/chain/iOVM_StateCommitmentChain.sol"; import { iOVM_StateCommitmentChain } from "../../iOVM/chain/iOVM_StateCommitmentChain.sol";
/* Contract Imports */ /* Contract Imports */
import { OVM_BaseCrossDomainMessenger } from "./OVM_BaseCrossDomainMessenger.sol"; import { Abs_BaseCrossDomainMessenger } from "./Abs_BaseCrossDomainMessenger.sol";
/** /**
* @title OVM_L1CrossDomainMessenger * @title OVM_L1CrossDomainMessenger
...@@ -26,7 +26,7 @@ import { OVM_BaseCrossDomainMessenger } from "./OVM_BaseCrossDomainMessenger.sol ...@@ -26,7 +26,7 @@ import { OVM_BaseCrossDomainMessenger } from "./OVM_BaseCrossDomainMessenger.sol
* Compiler used: solc * Compiler used: solc
* Runtime target: EVM * Runtime target: EVM
*/ */
contract OVM_L1CrossDomainMessenger is iOVM_L1CrossDomainMessenger, OVM_BaseCrossDomainMessenger, Lib_AddressResolver { contract OVM_L1CrossDomainMessenger is iOVM_L1CrossDomainMessenger, Abs_BaseCrossDomainMessenger, Lib_AddressResolver {
/*************** /***************
* Constructor * * Constructor *
......
...@@ -12,16 +12,17 @@ import { iOVM_L1MessageSender } from "../../iOVM/precompiles/iOVM_L1MessageSende ...@@ -12,16 +12,17 @@ import { iOVM_L1MessageSender } from "../../iOVM/precompiles/iOVM_L1MessageSende
import { iOVM_L2ToL1MessagePasser } from "../../iOVM/precompiles/iOVM_L2ToL1MessagePasser.sol"; import { iOVM_L2ToL1MessagePasser } from "../../iOVM/precompiles/iOVM_L2ToL1MessagePasser.sol";
/* Contract Imports */ /* Contract Imports */
import { OVM_BaseCrossDomainMessenger } from "./OVM_BaseCrossDomainMessenger.sol"; import { Abs_BaseCrossDomainMessenger } from "./Abs_BaseCrossDomainMessenger.sol";
/** /**
* @title OVM_L2CrossDomainMessenger * @title OVM_L2CrossDomainMessenger
* @dev The L2 Cross Domain Messenger contract sends messages from L2 to L1, and is the entry point for L2 messages sent via the L1 Cross Domain Messenger. * @dev The L2 Cross Domain Messenger contract sends messages from L2 to L1, and is the entry point
* for L2 messages sent via the L1 Cross Domain Messenger.
* *
* Compiler used: optimistic-solc * Compiler used: optimistic-solc
* Runtime target: OVM * Runtime target: OVM
*/ */
contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, OVM_BaseCrossDomainMessenger, Lib_AddressResolver { contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, Abs_BaseCrossDomainMessenger, Lib_AddressResolver {
/*************** /***************
* Constructor * * Constructor *
......
...@@ -86,6 +86,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -86,6 +86,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
* @return Reference to the batch storage container. * @return Reference to the batch storage container.
*/ */
function batches() function batches()
override
public public
view view
returns ( returns (
...@@ -102,6 +103,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -102,6 +103,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
* @return Reference to the queue storage container. * @return Reference to the queue storage container.
*/ */
function queue() function queue()
override
public public
view view
returns ( returns (
...@@ -114,7 +116,8 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -114,7 +116,8 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
} }
/** /**
* @inheritdoc iOVM_CanonicalTransactionChain * Retrieves the total number of elements submitted.
* @return _totalElements Total submitted elements.
*/ */
function getTotalElements() function getTotalElements()
override override
...@@ -129,7 +132,8 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -129,7 +132,8 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
} }
/** /**
* @inheritdoc iOVM_CanonicalTransactionChain * Retrieves the total number of batches submitted.
* @return _totalBatches Total submitted batches.
*/ */
function getTotalBatches() function getTotalBatches()
override override
...@@ -143,7 +147,8 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -143,7 +147,8 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
} }
/** /**
* @inheritdoc iOVM_CanonicalTransactionChain * Returns the index of the next element to be enqueued.
* @return Index for the next queue element.
*/ */
function getNextQueueIndex() function getNextQueueIndex()
override override
...@@ -158,7 +163,9 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -158,7 +163,9 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
} }
/** /**
* @inheritdoc iOVM_CanonicalTransactionChain * Gets the queue element at a particular index.
* @param _index Index of the queue element to access.
* @return _element Queue element at the given index.
*/ */
function getQueueElement( function getQueueElement(
uint256 _index uint256 _index
...@@ -189,7 +196,8 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -189,7 +196,8 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
} }
/** /**
* @inheritdoc iOVM_CanonicalTransactionChain * Get the number of queue elements which have not yet been included.
* @return Number of pending queue elements.
*/ */
function getNumPendingQueueElements() function getNumPendingQueueElements()
override override
...@@ -203,7 +211,9 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -203,7 +211,9 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
} }
/** /**
* @inheritdoc iOVM_CanonicalTransactionChain * Retrieves the length of the queue, including
* both pending and canonical transactions.
* @return Length of the queue.
*/ */
function getQueueLength() function getQueueLength()
override override
...@@ -220,7 +230,10 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -220,7 +230,10 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
} }
/** /**
* @inheritdoc iOVM_CanonicalTransactionChain * Adds a transaction to the queue.
* @param _target Target L2 contract to send the transaction to.
* @param _gasLimit Gas limit for the enqueued L2 transaction.
* @param _data Transaction data.
*/ */
function enqueue( function enqueue(
address _target, address _target,
...@@ -297,7 +310,8 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -297,7 +310,8 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
} }
/** /**
* @inheritdoc iOVM_CanonicalTransactionChain * Appends a given number of queued transactions as a single batch.
* @param _numQueuedTransactions Number of transactions to append.
*/ */
function appendQueueBatch( function appendQueueBatch(
uint256 _numQueuedTransactions uint256 _numQueuedTransactions
...@@ -347,7 +361,12 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -347,7 +361,12 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
} }
/** /**
* @inheritdoc iOVM_CanonicalTransactionChain * Allows the sequencer to append a batch of transactions.
* @dev This function uses a custom encoding scheme for efficiency reasons.
* .param _shouldStartAtElement Specific batch we expect to start appending to.
* .param _totalElementsToAppend Total number of batch elements we expect to append.
* .param _contexts Array of batch contexts.
* .param _transactionDataFields Array of raw transaction data.
*/ */
function appendSequencerBatch() function appendSequencerBatch()
override override
...@@ -480,7 +499,12 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -480,7 +499,12 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
} }
/** /**
* @inheritdoc iOVM_CanonicalTransactionChain * Verifies whether a transaction is included in the chain.
* @param _transaction Transaction to verify.
* @param _txChainElement Transaction chain element corresponding to the transaction.
* @param _batchHeader Header of the batch the transaction was included in.
* @param _inclusionProof Inclusion proof for the provided transaction chain element.
* @return True if the transaction exists in the CTC, false if not.
*/ */
function verifyTransaction( function verifyTransaction(
Lib_OVMCodec.Transaction memory _transaction, Lib_OVMCodec.Transaction memory _transaction,
......
...@@ -13,7 +13,7 @@ import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol"; ...@@ -13,7 +13,7 @@ import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol";
* @dev The State Manager contract holds all storage values for contracts in the OVM. It can only be written to by the * @dev The State Manager contract holds all storage values for contracts in the OVM. It can only be written to by the
* the Execution Manager and State Transitioner. It runs on L1 during the setup and execution of a fraud proof. * the Execution Manager and State Transitioner. It runs on L1 during the setup and execution of a fraud proof.
* The same logic runs on L2, but has been implemented as a precompile in the L2 go-ethereum client * The same logic runs on L2, but has been implemented as a precompile in the L2 go-ethereum client
* (see https://github.com/ethereum-optimism/go-ethereum/blob/master/core/vm/ovm_state_manager.go) * (see https://github.com/ethereum-optimism/go-ethereum/blob/master/core/vm/ovm_state_manager.go).
* *
* Compiler used: solc * Compiler used: solc
* Runtime target: EVM * Runtime target: EVM
......
...@@ -6,7 +6,6 @@ import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolve ...@@ -6,7 +6,6 @@ import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolve
/* Interface Imports */ /* Interface Imports */
import { iOVM_ERC20 } from "../../iOVM/precompiles/iOVM_ERC20.sol"; import { iOVM_ERC20 } from "../../iOVM/precompiles/iOVM_ERC20.sol";
import { iOVM_BaseCrossDomainMessenger } from "../../iOVM/bridge/iOVM_BaseCrossDomainMessenger.sol";
/** /**
* @title OVM_ETH * @title OVM_ETH
......
...@@ -6,7 +6,7 @@ import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolve ...@@ -6,7 +6,7 @@ import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolve
/// Minimal contract to be inherited by contracts consumed by users that provide /// Minimal contract to be inherited by contracts consumed by users that provide
/// data for fraud proofs /// data for fraud proofs
abstract contract OVM_FraudContributor is Lib_AddressResolver { abstract contract Abs_FraudContributor is Lib_AddressResolver {
/// Decorate your functions with this modifier to store how much total gas was /// Decorate your functions with this modifier to store how much total gas was
/// consumed by the sender, to reward users fairly /// consumed by the sender, to reward users fairly
modifier contributesToFraudProof(bytes32 preStateRoot, bytes32 txHash) { modifier contributesToFraudProof(bytes32 preStateRoot, bytes32 txHash) {
......
...@@ -15,7 +15,7 @@ import { iOVM_StateCommitmentChain } from "../../iOVM/chain/iOVM_StateCommitment ...@@ -15,7 +15,7 @@ import { iOVM_StateCommitmentChain } from "../../iOVM/chain/iOVM_StateCommitment
import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalTransactionChain.sol"; import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalTransactionChain.sol";
/* Contract Imports */ /* Contract Imports */
import { OVM_FraudContributor } from "./OVM_FraudContributor.sol"; import { Abs_FraudContributor } from "./Abs_FraudContributor.sol";
...@@ -28,7 +28,7 @@ import { OVM_FraudContributor } from "./OVM_FraudContributor.sol"; ...@@ -28,7 +28,7 @@ import { OVM_FraudContributor } from "./OVM_FraudContributor.sol";
* Compiler used: solc * Compiler used: solc
* Runtime target: EVM * Runtime target: EVM
*/ */
contract OVM_FraudVerifier is Lib_AddressResolver, OVM_FraudContributor, iOVM_FraudVerifier { contract OVM_FraudVerifier is Lib_AddressResolver, Abs_FraudContributor, iOVM_FraudVerifier {
/******************************************* /*******************************************
* Contract Variables: Internal Accounting * * Contract Variables: Internal Accounting *
......
...@@ -21,7 +21,7 @@ import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol"; ...@@ -21,7 +21,7 @@ import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol";
import { iOVM_StateManagerFactory } from "../../iOVM/execution/iOVM_StateManagerFactory.sol"; import { iOVM_StateManagerFactory } from "../../iOVM/execution/iOVM_StateManagerFactory.sol";
/* Contract Imports */ /* Contract Imports */
import { OVM_FraudContributor } from "./OVM_FraudContributor.sol"; import { Abs_FraudContributor } from "./Abs_FraudContributor.sol";
/** /**
* @title OVM_StateTransitioner * @title OVM_StateTransitioner
...@@ -37,7 +37,7 @@ import { OVM_FraudContributor } from "./OVM_FraudContributor.sol"; ...@@ -37,7 +37,7 @@ import { OVM_FraudContributor } from "./OVM_FraudContributor.sol";
* Compiler used: solc * Compiler used: solc
* Runtime target: EVM * Runtime target: EVM
*/ */
contract OVM_StateTransitioner is Lib_AddressResolver, OVM_FraudContributor, iOVM_StateTransitioner { contract OVM_StateTransitioner is Lib_AddressResolver, Abs_FraudContributor, iOVM_StateTransitioner {
/******************* /*******************
* Data Structures * * Data Structures *
......
...@@ -3,9 +3,9 @@ pragma solidity >0.5.0 <0.8.0; ...@@ -3,9 +3,9 @@ pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
/** /**
* @title iOVM_BaseCrossDomainMessenger * @title iAbs_BaseCrossDomainMessenger
*/ */
interface iOVM_BaseCrossDomainMessenger { interface iAbs_BaseCrossDomainMessenger {
/********** /**********
* Events * * Events *
......
...@@ -6,12 +6,12 @@ pragma experimental ABIEncoderV2; ...@@ -6,12 +6,12 @@ pragma experimental ABIEncoderV2;
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol"; import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/* Interface Imports */ /* Interface Imports */
import { iOVM_BaseCrossDomainMessenger } from "./iOVM_BaseCrossDomainMessenger.sol"; import { iAbs_BaseCrossDomainMessenger } from "./iAbs_BaseCrossDomainMessenger.sol";
/** /**
* @title iOVM_L1CrossDomainMessenger * @title iOVM_L1CrossDomainMessenger
*/ */
interface iOVM_L1CrossDomainMessenger is iOVM_BaseCrossDomainMessenger { interface iOVM_L1CrossDomainMessenger is iAbs_BaseCrossDomainMessenger {
/******************* /*******************
* Data Structures * * Data Structures *
......
...@@ -3,12 +3,12 @@ pragma solidity >0.5.0 <0.8.0; ...@@ -3,12 +3,12 @@ pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
/* Interface Imports */ /* Interface Imports */
import { iOVM_BaseCrossDomainMessenger } from "./iOVM_BaseCrossDomainMessenger.sol"; import { iAbs_BaseCrossDomainMessenger } from "./iAbs_BaseCrossDomainMessenger.sol";
/** /**
* @title iOVM_L2CrossDomainMessenger * @title iOVM_L2CrossDomainMessenger
*/ */
interface iOVM_L2CrossDomainMessenger is iOVM_BaseCrossDomainMessenger { interface iOVM_L2CrossDomainMessenger is iAbs_BaseCrossDomainMessenger {
/******************** /********************
* Public Functions * * Public Functions *
......
...@@ -5,6 +5,9 @@ pragma experimental ABIEncoderV2; ...@@ -5,6 +5,9 @@ pragma experimental ABIEncoderV2;
/* Library Imports */ /* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol"; import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/* Interface Imports */
import { iOVM_ChainStorageContainer } from "./iOVM_ChainStorageContainer.sol";
/** /**
* @title iOVM_CanonicalTransactionChain * @title iOVM_CanonicalTransactionChain
*/ */
...@@ -60,6 +63,29 @@ interface iOVM_CanonicalTransactionChain { ...@@ -60,6 +63,29 @@ interface iOVM_CanonicalTransactionChain {
* Public Functions * * Public Functions *
********************/ ********************/
/**
* Accesses the batch storage container.
* @return Reference to the batch storage container.
*/
function batches()
external
view
returns (
iOVM_ChainStorageContainer
);
/**
* Accesses the queue storage container.
* @return Reference to the queue storage container.
*/
function queue()
external
view
returns (
iOVM_ChainStorageContainer
);
/** /**
* Retrieves the total number of elements submitted. * Retrieves the total number of elements submitted.
* @return _totalElements Total submitted elements. * @return _totalElements Total submitted elements.
...@@ -93,9 +119,23 @@ interface iOVM_CanonicalTransactionChain { ...@@ -93,9 +119,23 @@ interface iOVM_CanonicalTransactionChain {
uint40 uint40
); );
/**
* Gets the queue element at a particular index.
* @param _index Index of the queue element to access.
* @return _element Queue element at the given index.
*/
function getQueueElement(
uint256 _index
)
external
view
returns (
Lib_OVMCodec.QueueElement memory _element
);
/** /**
* Get the number of queue elements which have not yet been included. * Get the number of queue elements which have not yet been included.
* @return Length of the queue. * @return Number of pending queue elements.
*/ */
function getNumPendingQueueElements() function getNumPendingQueueElements()
external external
...@@ -116,19 +156,6 @@ interface iOVM_CanonicalTransactionChain { ...@@ -116,19 +156,6 @@ interface iOVM_CanonicalTransactionChain {
uint40 uint40
); );
/**
* Gets the queue element at a particular index.
* @param _index Index of the queue element to access.
* @return _element Queue element at the given index.
*/
function getQueueElement(
uint256 _index
)
external
view
returns (
Lib_OVMCodec.QueueElement memory _element
);
/** /**
* Adds a transaction to the queue. * Adds a transaction to the queue.
......
...@@ -3,12 +3,12 @@ pragma solidity >0.5.0 <0.8.0; ...@@ -3,12 +3,12 @@ pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
/* Contract Imports */ /* Contract Imports */
import { iOVM_BaseCrossDomainMessenger } from "../../iOVM/bridge/iOVM_BaseCrossDomainMessenger.sol"; import { iAbs_BaseCrossDomainMessenger } from "../../iOVM/bridge/iAbs_BaseCrossDomainMessenger.sol";
/** /**
* @title mockOVM_CrossDomainMessenger * @title mockOVM_CrossDomainMessenger
*/ */
contract mockOVM_CrossDomainMessenger is iOVM_BaseCrossDomainMessenger { contract mockOVM_CrossDomainMessenger is iAbs_BaseCrossDomainMessenger {
/*********** /***********
* Structs * * Structs *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment