# Heimdall

Heimdall is the heart of the Ramestta network. It manages validators, block producer selection, spans, the state-sync mechanism between Polygon and Ramestta, and other essential aspects of the system. It uses the Cosmos-SDK and a forked version of Tendermint, called Peppermint. Heimdall removes some of the modules from Cosmos-SDK but mostly uses a customized version of it while following the same pattern.

## Heimdall and Bor

Heimdall’s `bor` module is responsible for managing span intervals and coordinating interactions with the Bor chain. Specifically, it determines when a new span can be proposed on Heimdall based on the current block number `n` and the current span `span`. A new span proposal is permissible when the current Bor chain block number `n` falls within the range of `span.StartBlock` and `span.EndBlock` (inclusive of `StartBlock` and exclusive of `EndBlock`). Validators on the Heimdall chain can propose a new span when these conditions are met.

### Messages <a href="#messages" id="messages"></a>

#### MsgProposeSpan <a href="#msgproposespan" id="msgproposespan"></a>

The `MsgProposeSpan` message plays a crucial role in setting up the validator committee for a specific span and records a new span in the Heimdall state. This message is detailed in the Heimdall source code at bor/handler.go#L27.

```
// MsgProposeSpan creates msg propose span
type MsgProposeSpan struct {
 ID         uint64                  `json:"span_id"`
 Proposer   hmTypes.HeimdallAddress `json:"proposer"`
 StartBlock uint64                  `json:"start_block"`
 EndBlock   uint64                  `json:"end_block"`
 ChainID    string                  `json:"bor_chain_id"`
}
```

**Selection of Producers**

The process for choosing producers from among all validators involves a two-step mechanism:

**1. Slot Allocation Based on Validator Power:** Each validator is assigned a number of slots proportional to their power. For instance, a validator with a power rating of 10 will receive 10 slots, while one with a power rating of 20 will receive 20 slots. This method ensures that validators with higher power have a correspondingly higher chance of being selected.

**2. Shuffling and Selection:** All allocated slots are then shuffled using a `seed` derived from the Polygon (MATIC 1.0) block hash corresponding to each span `n`. The first `producerCount` producers are selected from this shuffled list. The `bor` module on Heimdall employs the Polygon 2.0 shuffle algorithm for this selection process. The algorithm’s implementation can be viewed at bor/selection.go.

* This method of selection ensures that the process is both fair and weighted according to the validators’ power, thereby maintaining a balanced and proportional representation in the span committee.

```
// SelectNextProducers selects producers for the next span by converting power to slots
// spanEligibleVals - all validators eligible for next span
func SelectNextProducers(blkHash common.Hash, spanEligibleVals []hmTypes.Validator, producerCount uint64) (selectedIDs []uint64, err error) {
 if len(spanEligibleVals) <= int(producerCount) {
  for _, val := range spanEligibleVals {
   selectedIDs = append(selectedIDs, uint64(val.ID))
  }
  return
 }

 // extract seed from hash
 seed := helper.ToBytes32(blkHash.Bytes()[:32])
 validatorIndices := convertToSlots(spanEligibleVals)
 selectedIDs, err = ShuffleList(validatorIndices, seed)
 if err != nil {
  return
 }
 return selectedIDs[:producerCount], nil
}

// converts validator power to slots
func convertToSlots(vals []hmTypes.Validator) (validatorIndices []uint64) {
 for _, val := range vals {
  for val.VotingPower >= types.SlotCost {
   validatorIndices = append(validatorIndices, uint64(val.ID))
   val.VotingPower = val.VotingPower - types.SlotCost
  }
 }
 return validatorIndices
}
```

### Types <a href="#types" id="types"></a>

Here are the span details that Heimdall uses:

```
// Span structure
type Span struct {
 ID                uint64       `json:"span_id" yaml:"span_id"`
 StartBlock        uint64       `json:"start_block" yaml:"start_block"`
 EndBlock          uint64       `json:"end_block" yaml:"end_block"`
 ValidatorSet      ValidatorSet `json:"validator_set" yaml:"validator_set"`
 SelectedProducers []Validator  `json:"selected_producers" yaml:"selected_producers"`
 ChainID           string       `json:"bor_chain_id" yaml:"bor_chain_id"`
}
```

### Parameters <a href="#parameters" id="parameters"></a>

The Bor module contains the following parameters:

| Key             | Type   | Default value                        | Duration (\*)                 |
| --------------- | ------ | ------------------------------------ | ----------------------------- |
| SprintDuration. | uint64 | 16 blocks                            | 32 seconds                    |
| SpanDuration    | uint64 | 100 \* SprintDuration = 1,600 blocks | 3,200 seconds (53min and 20s) |
| ProducerCount   | uint64 | 4 blocks                             | 8 seconds                     |

(\*): Given that blocks are produced every 2 seconds on Bor.

### CLI Commands <a href="#cli-commands" id="cli-commands"></a>

#### Span propose tx <a href="#span-propose-tx" id="span-propose-tx"></a>

```
heimdallcli tx bor propose-span \
 --start-block <start-block> \
 --chain-id <heimdall-chain-id>
 
```

#### Query current span <a href="#query-current-span" id="query-current-span"></a>

```
heimdallcli query bor span latest-span --chain-id <heimdall-chain-id>
```

Expected output:

```
{
  "span_id":2,
  "start_block":6656,
  "end_block":13055,
  "validator_set":{
    "validators":[
      {
        "ID":1,
        "startEpoch":0,
        "endEpoch":0,
        "power":1,
        "pubKey":"0x04b12d8b2f6e3d45a7ace12c4b2158f79b95e4c28ebe5ad54c439be9431d7fc9dc1164210bf6a5c3b8523528b931e772c86a307e8cff4b725e6b4a77d21417bf19",
        "signer":"0x6c468cf8c9879006e22ec4029696e005c2319c9d",
        "last_updated":"",
        "accum":0
      }
    ],
    "proposer":{
      "ID":1,
      "startEpoch":0,
      "endEpoch":0,
      "power":1,
      "pubKey":"0x04b12d8b2f6e3d45a7ace12c4b2158f79b95e4c28ebe5ad54c439be9431d7fc9dc1164210bf6a5c3b8523528b931e772c86a307e8cff4b725e6b4a77d21417bf19",
      "signer":"0x6c468cf8c9879006e22ec4029696e005c2319c9d",
      "last_updated":"",
      "accum":0
    }
  },
  "selected_producers":[
    {
      "ID":1,
      "startEpoch":0,
      "endEpoch":0,
      "power":1,
      "pubKey":"0x04b12d8b2f6e3d45a7ace12c4b2158f79b95e4c28ebe5ad54c439be9431d7fc9dc1164210bf6a5c3b8523528b931e772c86a307e8cff4b725e6b4a77d21417bf19",
      "signer":"0x6c468cf8c9879006e22ec4029696e005c2319c9d",
      "last_updated":"",
      "accum":0
    }
  ],
  "bor_chain_id":"1370"
}
```

#### Query span by id <a href="#query-span-by-id" id="query-span-by-id"></a>

```
heimdallcli query bor span --span-id <span-id> --chain-id <heimdall-chain-id>
```

It prints the result in same format as above.

#### Parameters <a href="#parameters_1" id="parameters_1"></a>

To print all params;

```
heimdalldcli query bor params
```

Expected Result:

```
sprint_duration: 16
span_duration: 1600
producer_count: 4
```

### REST APIs <a href="#rest-apis" id="rest-apis"></a>

| Name            | Method | Endpoint          |
| --------------- | ------ | ----------------- |
| Span details    | GET    | /bor/span/span-id |
| Get latest span | GET    | /bor/latest-span  |
| Get params      | GET    | /bor/params       |

## Authentication

Heimdall’s `auth` module is responsible for specifying the base transaction and account types for an application. It contains the ante handler, where all basic transaction validity checks (signatures, nonces, auxiliary fields) are performed, and exposes the account keeper, which allows other modules to read, write, and modify accounts.

### Gas and fees <a href="#gas-and-fees" id="gas-and-fees"></a>

Fees serve two purposes for an operator of the network.

Fees limit the growth of the state stored by every full node and allow for general purpose censorship of transactions of little economic value. Fees are best suited as an anti-spam mechanism where validators are disinterested in the use of the network and identities of users.

Since Heimdall doesn’t support custom contract or code for any transaction, it uses fixed cost transactions. For fixed cost transactions, the validator can top up their accounts on the Ethereum chain and get tokens on Heimdall using the [Topup](https://docs.polygon.technology/pos/architecture/heimdall/topup/) module.

### Types <a href="#types" id="types"></a>

Besides accounts (specified in State), the types exposed by the auth module are **StdSignature**, the combination of an optional public key and a cryptographic signature as a byte array, **StdTx**, a struct that implements the `sdk.Tx` interface using **StdSignature**, and **StdSignDoc**, a replay-prevention structure for **StdTx** which transaction senders must sign over.

#### StdSignature <a href="#stdsignature" id="stdsignature"></a>

A `StdSignature` is the types of a byte array.

```
// StdSignature represents a sig
type StdSignature []byte
```

#### StdTx <a href="#stdtx" id="stdtx"></a>

A `StdTx` is a struct that implements the `sdk.Tx` interface, and is likely to be generic enough to serve the purposes of many types of transactions.

```
type StdTx struct {
  Msg       sdk.Msg      `json:"msg" yaml:"msg"`
  Signature StdSignature `json:"signature" yaml:"signature"`
  Memo      string       `json:"memo" yaml:"memo"`
}
```

#### StdSignDoc <a href="#stdsigndoc" id="stdsigndoc"></a>

A `StdSignDoc` is a replay-prevention structure to be signed over, which ensures that any submitted transaction (which is simply a signature over a particular byte string) will only be executable once on a Heimdall.

```
// StdSignDoc is replay-prevention structure.
// It includes the result of msg.GetSignBytes(),
// as well as the ChainID (prevent cross chain replay)
// and the Sequence numbers for each signature (prevent
// inchain replay and enforce tx ordering per account).
type StdSignDoc struct {
 ChainID       string          `json:"chain_id" yaml:"chain_id"`
 AccountNumber uint64          `json:"account_number" yaml:"account_number"`
 Sequence      uint64          `json:"sequence" yaml:"sequence"`
 Msg           json.RawMessage `json:"msg" yaml:"msg"`
 Memo          string          `json:"memo" yaml:"memo"`
}
```

#### Account <a href="#account" id="account"></a>

It manages addresses, coins and nonce for transactions. It also signs and validates transactions.

```
type BaseAccount struct {
  Address types.HeimdallAddress `json:"address" yaml:"address"`
  Coins types.Coins `json:"coins" yaml:"coins"`
  PubKey crypto.PubKey `json:"public_key" yaml:"public_key"`
  AccountNumber uint64 `json:"account_number" yaml:"account_number"`
  Sequence uint64 `json:"sequence" yaml:"sequence"`
}
```

### Parameters <a href="#parameters" id="parameters"></a>

The auth module contains the following parameters:

| Key                    | Type   | Default value      |
| ---------------------- | ------ | ------------------ |
| MaxMemoCharacters      | uint64 | 256                |
| TxSigLimit             | uint64 | 7                  |
| TxSizeCostPerByte      | uint64 | 10                 |
| SigVerifyCostED25519   | uint64 | 590                |
| SigVerifyCostSecp256k1 | uint64 | 1000               |
| DefaultMaxTxGas        | uint64 | 1000000            |
| DefaultTxFees          | string | “1000000000000000” |

### CLI commands <a href="#cli-commands" id="cli-commands"></a>

#### Show account <a href="#show-account" id="show-account"></a>

To print account related data into Heimdall;

```
heimdalld show-account
```

Expected Result:

```
{
 "address": "0x68243159a498cf20d945cf3E4250918278BA538E",
 "pub_key": "0x040a9f6879c7cdab7ecc67e157cda15e8b2ddbde107a04bc22d02f50032e393f6360a05e85c7c1ecd201ad30dfb886af12dd02b47e4463f6f0f6f94159dc9f10b8"
}
```

#### Account and coin details <a href="#account-and-coin-details" id="account-and-coin-details"></a>

To display account details, coins, sequence and account number;

```
heimdallcli query auth account 0x68243159a498cf20d945cf3E4250918278BA538E --trust-node
```

Expected Result:

```
address: 0x68243159a498cf20d945cf3e4250918278ba538e
coins:
- denom: RAMA
    amount:
    i: "1000000000000000000000"
pubkey: ""
accountnumber: 0
sequence: 0
```

#### Parameters <a href="#parameters_1" id="parameters_1"></a>

To print all params;

```
heimdallcli query auth params
```

Expected Result:

```
max_memo_characters: 256
tx_sig_limit: 7
tx_size_cost_per_byte: 10
sig_verify_cost_ed25519: 590
sig_verify_cost_secp256k1: 1000
max_tx_gas: 1000000
tx_fees: "1000000000000000"
```

### REST APIs <a href="#rest-apis" id="rest-apis"></a>

| Name                     | Endpoint                          | Description                                |
| ------------------------ | --------------------------------- | ------------------------------------------ |
| Account details          | /auth/accounts/{address}          | Returns all details for an address         |
| Account sequence details | /auth/accounts/{address}/sequence | Returns only necessary details for signing |
| Auth params              | /auth/params                      | Returns all params auth module uses        |

## Key management

Each validator uses two keys to manage validator related activities on Ramestta. The Signer key is kept on the node and is generally considered a `hot` wallet, whereas the Owner key is supposed to kept very secure, is used infrequently, and is generally considered a `cold` wallet. The staked funds are controlled by the Owner key.

This separation of responsibilities has been done to ensure an efficient tradeoff between security and ease of use. Both keys are Polygon compatible addresses and work exactly the same manner. And yes, it is possible to have same Owner and Signer keys.

### Signer key <a href="#signer-key" id="signer-key"></a>

The signer key is an address that is used for signing Heimdall blocks, checkpoints, and other signing related activities. This key’s private key will be on the Validator node for signing purposes. It cannot manage stake, rewards or delegations.

The validator must keep two types of balances on this address:

* Rama tokens on Heimdall (through Topup transactions) to perform validator responsibilities on Heimdall
* MATIC on Polygon chain to send checkpoints on Polygon

### Owner key <a href="#owner-key" id="owner-key"></a>

The owner key is an address that is used for staking, re-stake, changing the signer key, withdraw rewards and manage delegation related parameters on the Polygon chain. The private key for this key must be secure at all cost.

All transactions through this key will be performed on the Polygon chain.

### Signer change <a href="#signer-change" id="signer-change"></a>

Following event is generated in case of signer change on Polygon chain on `StakingInfo.sol`:&#x20;

```
// Signer change
event SignerChange(
  uint256 indexed validatorId,
  address indexed oldSigner,
  address indexed newSigner,
  bytes signerPubkey
);
```

Heimdall bridge processes these events and sends transactions on Heimdall to change state based on the events.

\
Validation

Heimdall’s “Ante Handler” plays a crucial role in the integrity and efficiency of transaction processing. It is primarily responsible for the preliminary verification and validation of all transactions, ensuring that they meet the necessary criteria before being included in a block. This includes checking the sender’s balance to ensure there are sufficient funds to cover transaction fees and subsequently deducting these fees for successful transactions.

### Advanced Gas Management in Heimdall <a href="#advanced-gas-management-in-heimdall" id="advanced-gas-management-in-heimdall"></a>

#### Block and Transaction Gas Limits <a href="#block-and-transaction-gas-limits" id="block-and-transaction-gas-limits"></a>

Heimdall employs a gas limit system to regulate the computational and storage resources consumed by transactions and blocks. This system is designed to prevent excessive block sizes and ensure network stability.

**Block Gas Limit**

Each block in Heimdall has a maximum gas limit, constraining the total gas used by all transactions within the block. The sum of the gas used by each transaction in a block must not exceed this limit:

```
 block.GasLimit >= sum(tx1.GasUsed + tx2.GasUsed + ..... + txN.GasUsed)
```

The maximum block gas limit and block size are specified as part of the consensus parameters during the application setup, as seen in the Heimdall source code at app.go#L464-L471:

```
maxGasPerBlock   int64 = 10000000 // 10 Million
maxBytesPerBlock int64 = 22020096 // 21 MB

// Setting consensus parameters
ConsensusParams: &abci.ConsensusParams{
 Block: &abci.BlockParams{
  MaxBytes: maxBytesPerBlock,
  MaxGas:   maxGasPerBlock,
 },
 ...
},
```

**Transaction Gas Limit**

For individual transactions, the gas limit is determined by parameters in the `auth` module and can be modified through Heimdall’s governance (`gov`) module.

**Special Handling of Checkpoint Transactions**

Checkpoint transactions, which require Merkle proof verification on the Polygon chain, are treated distinctly. To streamline processing and avoid the overhead of additional Merkle proof verification, Heimdall restricts blocks containing a `MsgCheckpoint` transaction to just that one transaction:

```
// Gas requirement for checkpoint transaction
gasWantedPerCheckpoinTx sdk.Gas = 10000000 // 10 Million

// Special gas limit handling for checkpoint transactions
if stdTx.Msg.Type() == "checkpoint" && stdTx.Msg.Route() == "checkpoint" {
 gasForTx = gasWantedPerCheckpoinTx
}
```

### Enhanced Transaction Verification and Replay Protection <a href="#enhanced-transaction-verification-and-replay-protection" id="enhanced-transaction-verification-and-replay-protection"></a>

The Ante Handler in Heimdall is instrumental in ensuring the legitimacy and uniqueness of transactions. It performs a thorough verification of incoming transactions, including signature validation, as delineated in the source code at ante.go#L230-L266.

#### Sequence Number for Replay Protection <a href="#sequence-number-for-replay-protection" id="sequence-number-for-replay-protection"></a>

A critical aspect of transaction security in Heimdall is the use of a `sequenceNumber` in each transaction. This feature is a safeguard against replay attacks, where a transaction might be fraudulently or mistakenly repeated. To prevent such scenarios, the Ante Handler increments the sequence number for the sender’s account after each successful transaction. This incrementation ensures that each transaction is unique and that previous transactions cannot be replayed.

In summary, Heimdall’s Ante Handler, along with its sophisticated gas management and transaction verification systems, provides a robust framework for secure and efficient transaction processing. The careful balance of block and transaction gas limits, coupled with advanced replay protection mechanisms, ensures the smooth operation of the Heimdall chain within the Ramestta network.

## Balance transfers

Heimdall’s `bank` module handles balance transfers between accounts. This module corresponds to the `bank` module from cosmos-sdk.

### Messages <a href="#messages" id="messages"></a>

#### MsgSend <a href="#msgsend" id="msgsend"></a>

`MsgSend` handles transfer between accounts in Heimdall. Here is a structure for transaction message:

```
// MsgSend - high-level transaction of the coin module
type MsgSend struct {
 FromAddress types.HeimdallAddress `json:"from_address"`
 ToAddress   types.HeimdallAddress `json:"to_address"`
 Amount      types.Coins           `json:"amount"`
}
```

#### MsgMultiSend <a href="#msgmultisend" id="msgmultisend"></a>

`MsgMultiSend` handles multi transfer between account for Heimdall.

```
// MsgMultiSend - high-level transaction of the coin module
type MsgMultiSend struct {
 Inputs  []Input  `json:"inputs"`
 Outputs []Output `json:"outputs"`
}
```

### Parameters <a href="#parameters" id="parameters"></a>

The bank module contains the following parameters:

| Key           | Type | Default value |
| ------------- | ---- | ------------- |
| `sendenabled` | bool | true          |

### CLI Commands <a href="#cli-commands" id="cli-commands"></a>

#### Send Balance <a href="#send-balance" id="send-balance"></a>

Following command will send 1000 Rama tokens to mentioned `address`;

```
heimdallcli tx bank send <address> 1000rama --chain-id <chain-id>
```

## Staking <a href="#staking" id="staking"></a>

Staking module manages validator related transactions and state for Heimdall. Note that a validator stakes their tokens on the Polygon chain and becomes a validator. Respective validators send the transactions on Heimdall using necessary parameters to acknowledge the Polygon stake change. Once the majority of the validators agree on the change on the stake, this module saves the validator information on Heimdall state.

### Messages <a href="#messages" id="messages"></a>

<figure><img src="https://3495787697-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3iD8qFVyjPp1N1FbL3AL%2Fuploads%2F9hd9GLz7TbAePHnQW3jn%2Fstake-management-flow.svg?alt=media&#x26;token=3b432e64-3a80-40a9-8ddc-1d83da8c5a4e" alt=""><figcaption></figcaption></figure>

#### MsgValidatorJoin <a href="#msgvalidatorjoin" id="msgvalidatorjoin"></a>

`MsgValidatorJoin` handles the staking when a new validator joins the system. Once validator calls `stake` or `stakeFor` in `StakingManager.sol` on Polygon, and the new `Staked` event is emitted.

Source:&#x20;

```
/**
 * Staked event - emitted whenever new validator 
 * 
 * @param signer           Signer address for the validator
 * @param validatorId      Validator id
 * @param activationEpoch  Activation epoch for validator
 * @param amount           Staked amount
 * @param total            Total stake
 * @param signerPubKey     Signer public key (required by Heimdall/Tendermint)
 */
event Staked(
    address indexed signer,
    uint256 indexed validatorId,
    uint256 indexed activationEpoch,
    uint256 amount,
    uint256 total,
    bytes signerPubkey
);
```

`activationEpoch` is the checkpoint count from where a validator will become active on Heimdall.

Stake call on smart contract fails if slots are unavailable. Validator slots are the way to restrict a number of validators in the system. Slots are managed on Polygon smart contracts.

Here is `ValidatorJoin` message for Heimdall transaction:

```
type MsgValidatorJoin struct {
 From         hmTypes.HeimdallAddress `json:"from"`
 ID           hmTypes.ValidatorID     `json:"id"`
 SignerPubKey hmTypes.PubKey          `json:"pub_key"`
 TxHash       hmTypes.HeimdallHash    `json:"tx_hash"`
 LogIndex     uint64                  `json:"log_index"`
}
```

#### MsgStakeUpdate <a href="#msgstakeupdate" id="msgstakeupdate"></a>

`MsgStakeUpdate` handles the stake update when a validator the re-stakes or new delegation comes in. In either case, the new `StakeUpdate` event is emitted.

```
/**
 * Stake update event - emitted whenever stake gets updated 
 * 
 * @param validatorId      Validator id
 * @param newAmount        New staked amount
 */
event StakeUpdate(
 uint256 indexed validatorId, 
 uint256 indexed newAmount
);
```

Here is `MsgStakeUpdate` message for Heimdall transaction:

```
// MsgStakeUpdate represents stake update
type MsgStakeUpdate struct {
 From     hmTypes.HeimdallAddress `json:"from"`
 ID       hmTypes.ValidatorID     `json:"id"`
 TxHash   hmTypes.HeimdallHash    `json:"tx_hash"`
 LogIndex uint64                  `json:"log_index"`
}
```

#### MsgValidatorExit <a href="#msgvalidatorexit" id="msgvalidatorexit"></a>

`MsgValidatorExit` handles the validator exit process after a validator initiates the exit process on Ethereum. It emits `SignerUpdate` event.

```
/**
 * Unstake init event - emitted whenever validator initiates the exit
 * 
 * @param user                Signer
 * @param validatorId         Validator id
 * @param deactivationEpoch   Deactivation epoch for validator
 * @param amount              Unstaked amount
 */
event UnstakeInit(
    address indexed user,
    uint256 indexed validatorId,
    uint256 deactivationEpoch,
    uint256 indexed amount
);
```

Here is `MsgValidatorExit` message for Heimdall transaction:

```
type MsgValidatorExit struct {
 From     hmTypes.HeimdallAddress `json:"from"`
 ID       hmTypes.ValidatorID     `json:"id"`
 TxHash   hmTypes.HeimdallHash    `json:"tx_hash"`
 LogIndex uint64                  `json:"log_index"`
}
```

#### MsgSignerUpdate <a href="#msgsignerupdate" id="msgsignerupdate"></a>

`MsgSignerUpdate` handles the signer update when a validator updates signer key on Ethereum. It emits `SignerUpdate` event.

```
/**
 * Signer change event - emitted whenever signer key changes
 * 
 * @param validatorId      Validator id
 * @param oldSigner        Current old signer
 * @param newSigner        New signer
 * @param signerPubkey     New signer public key
 */
event SignerChange(
    uint256 indexed validatorId,
    address indexed oldSigner,
    address indexed newSigner,
    bytes signerPubkey
);
```

Here is `MsgSignerUpdate` message for Heimdall transaction:

```
// MsgSignerUpdate signer update struct
type MsgSignerUpdate struct {
 From            hmTypes.HeimdallAddress `json:"from"`
 ID              hmTypes.ValidatorID     `json:"id"`
 NewSignerPubKey hmTypes.PubKey          `json:"pubKey"`
 TxHash          hmTypes.HeimdallHash    `json:"tx_hash"`
 LogIndex        uint64                  `json:"log_index"`
}
```

### CLI Commands <a href="#cli-commands" id="cli-commands"></a>

#### Validator details <a href="#validator-details" id="validator-details"></a>

**By signer address**

```
heimdallcli query staking validator-info \
 --validator=<signer-address> \
 --chain-id <chain-id>
```

This command should display the following output:

```
{
    "ID":1,
    "startEpoch":0,
    "endEpoch":0,
    "power":10,
    "pubKey":"0x04b12d8b2f6e3d45a7ace12c4b2158f79b95e4c28ebe5ad54c439be9431d7fc9dc1164210bf6a5c3b8523528b931e772c86a307e8cff4b725e6b4a77d21417bf19",
    "signer":"0x6c468cf8c9879006e22ec4029696e005c2319c9d",
    "last_updated":0,
    "accum":0
}
```

**By validator address**

```
heimdallcli query staking validator-info \
 --id=<validator-id> \
 --chain-id=<chain-id>
```

This command should display the following output:

```
{
    "ID":1,
    "startEpoch":0,
    "endEpoch":0,
    "power":10,
    "pubKey":"0x04b12d8b2f6e3d45a7ace12c4b2158f79b95e4c28ebe5ad54c439be9431d7fc9dc1164210bf6a5c3b8523528b931e772c86a307e8cff4b725e6b4a77d21417bf19",
    "signer":"0x6c468cf8c9879006e22ec4029696e005c2319c9d",
    "last_updated":0,
    "accum":0
}
```

#### Validator join <a href="#validator-join" id="validator-join"></a>

This command sends validator join command through CLI:

```
heimdallcli tx staking validator-join \
 --signer-pubkey <signer-public-key> \
 --tx-hash <tx-hash>   \
 --log-index <log-index> \ 
 --chain-id <chain-id>
```

`tx-hash` value must be the same as Ethereum TX hash which emitted `Staked` event and `log-index` must be the same at which index the event is emitted.

### REST APIs <a href="#rest-apis" id="rest-apis"></a>

| Name                       | Method | Endpoint                        |
| -------------------------- | ------ | ------------------------------- |
| Get Heimdall validator set | GET    | /staking/validator-set          |
| Get validator details      | GET    | /staking/validator/validator-id |

All query APIs will result in following format:

```
{
 "height": "1",
 "result": {
  ...   
 }
}
```

Checkpoints

Checkpoints are vital components of the Ramestta network, representing snapshots of the Bor chain state. These checkpoints are attested by a majority of the validator set before being validated and submitted on Polygon contracts.

Heimdall, an integral part of this process, manages checkpoint functionalities using the `checkpoint` module. It coordinates with the Bor chain to verify checkpoint root hashes when a new checkpoint is proposed.

### Checkpoint life-cycle and types <a href="#checkpoint-life-cycle-and-types" id="checkpoint-life-cycle-and-types"></a>

#### Life-cycle <a href="#life-cycle" id="life-cycle"></a>

Heimdall selects the next proposer using Tendermint’s leader selection algorithm. The multi-stage checkpoint process is crucial due to potential failures when submitting checkpoints on the Polygon chain caused by factors like gas limit, network traffic, or high gas fees.

Each checkpoint has a validator as the proposer. The outcome of a checkpoint on the Polygon chain (success or failure) triggers an `ack` (acknowledgment) or `no-ack` (no acknowledgment) transaction, altering the proposer for the next checkpoint on Heimdall.

#### Types and structures <a href="#types-and-structures" id="types-and-structures"></a>

**Checkpoint block header**

```
type CheckpointBlockHeader struct {
 Proposer        types.HeimdallAddress `json:"proposer"`
 StartBlock      uint64                `json:"startBlock"`
 EndBlock        uint64                `json:"endBlock"`
 RootHash        types.HeimdallHash    `json:"rootHash"`
 AccountRootHash types.HeimdallHash    `json:"accountRootHash"`
 TimeStamp       uint64                `json:"timestamp"`
}
```

**Root hash calculation**

<figure><img src="https://3495787697-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3iD8qFVyjPp1N1FbL3AL%2Fuploads%2FqSM1BNJdomSBKT6jL1ki%2Fcheckpoint.svg?alt=media&#x26;token=ab9c66d5-2e04-40b1-a63a-36c1ebb7cec6" alt=""><figcaption></figcaption></figure>

The `RootHash` is calculated as a Merkle hash of Bor block hashes from `StartBlock` to `EndBlock`. The process involves hashing each block’s number, time, transaction hash, and receipt hash, then creating a Merkle root of these hashes.

```
blockHash = keccak256([number, time, tx hash, receipt hash])
```

Pseudocode for the root hash for `1` to `n` Bor blocks:

```
B(1) := keccak256([number, time, tx hash, receipt hash])
B(2) := keccak256([number, time, tx hash, receipt hash])
.
.
.
B(n) := keccak256([number, time, tx hash, receipt hash])

// checkpoint is Merkle root of all block hash
checkpoint's root hash = Merkel[B(1), B(2), ....., B(n)]
```

Here are some snippets of how checkpoint is created from Bor chain block headers.

Source:&#x20;

```
// Golang representation of block data used in checkpoint
blockData := crypto.Keccak256(appendBytes32(
 blockHeader.Number.Bytes(),
 new(big.Int).SetUint64(blockHeader.Time).Bytes(),
 blockHeader.TxHash.Bytes(),
 blockHeader.ReceiptHash.Bytes(),
))

// array of block hashes of Bor blocks
headers := [blockData1, blockData2, ..., blockDataN]

// merkel tree
tree := merkle.NewTreeWithOpts(merkle.TreeOptions{EnableHashSorting: false, DisableHashLeaves: true})
tree.Generate(convert(headers), sha3.NewLegacyKeccak256())

// create checkpoint's root hash
rootHash := tree.Root().Hash
```

#### AccountRootHash <a href="#accountroothash" id="accountroothash"></a>

`AccountRootHash` is the hash of the validator account-related information that needs to pass to the Polygon chain at each checkpoint.

```
eachAccountHash := keccak256([validator id, withdraw fee, slash amount])
```

Pseudocode for the account root hash for `1` to `n` Bor blocks:

```
B(1) := keccak256([validator id, withdraw fee, slash amount])
B(2) := keccak256([validator id, withdraw fee, slash amount])
.
.
.
B(n) := keccak256([validator id, withdraw fee, slash amount])

// account root hash is Merkle root of all block hash
checkpoint's account root hash = Merkel[B(1), B(2), ....., B(n)]
```

Golang code for the account hash can be found here:&#x20;

```
// DividendAccount contains Fee, Slashed amount
type DividendAccount struct {
 ID            DividendAccountID `json:"ID"`
 FeeAmount     string            `json:"feeAmount"`     // string representation of big.Int
 SlashedAmount string            `json:"slashedAmount"` // string representation of big.Int
}

// calculate hash for particular account
func (da DividendAccount) CalculateHash() ([]byte, error) {
 fee, _ := big.NewInt(0).SetString(da.FeeAmount, 10)
 slashAmount, _ := big.NewInt(0).SetString(da.SlashedAmount, 10)
 divAccountHash := crypto.Keccak256(appendBytes32(
  new(big.Int).SetUint64(uint64(da.ID)).Bytes(),
  fee.Bytes(),
  slashAmount.Bytes(),
 ))

 return divAccountHash, nil
}
```

### Messages in checkpoint module <a href="#messages-in-checkpoint-module" id="messages-in-checkpoint-module"></a>

#### MsgCheckpoint <a href="#msgcheckpoint" id="msgcheckpoint"></a>

`MsgCheckpoint` handles checkpoint verification on Heimdall, utilizing RLP encoding for Polygon chain verification. It prioritizes transactions with high gas consumption to ensure only one `MsgCheckpoint` transaction per block.

```
// MsgCheckpoint represents checkpoint transaction
type MsgCheckpoint struct {
 Proposer        types.HeimdallAddress `json:"proposer"`
 StartBlock      uint64                `json:"startBlock"`
 EndBlock        uint64                `json:"endBlock"`
 RootHash        types.HeimdallHash    `json:"rootHash"`
 AccountRootHash types.HeimdallHash    `json:"accountRootHash"`
}
```

#### MsgCheckpointAck <a href="#msgcheckpointack" id="msgcheckpointack"></a>

`MsgCheckpointAck` manages successful checkpoint submissions, updating the checkpoint count and clearing the `checkpointBuffer`.

```
// MsgCheckpointAck represents checkpoint ack transaction if checkpoint is successful
type MsgCheckpointAck struct {
 From        types.HeimdallAddress `json:"from"`
 HeaderBlock uint64                `json:"headerBlock"`
 TxHash      types.HeimdallHash    `json:"tx_hash"`
 LogIndex    uint64                `json:"log_index"`
}
```

#### MsgCheckpointNoAck <a href="#msgcheckpointnoack" id="msgcheckpointnoack"></a>

`MsgCheckpointNoAck` deals with unsuccessful checkpoints or offline proposers, allowing a timeout period before selecting a new proposer.

```
// MsgCheckpointNoAck represents checkpoint no-ack transaction
type MsgCheckpointNoAck struct {
 From types.HeimdallAddress `json:"from"`
}
```

### Parameters and CLI commands <a href="#parameters-and-cli-commands" id="parameters-and-cli-commands"></a>

#### Parameters <a href="#parameters" id="parameters"></a>

The checkpoint module contains the following parameters:

| Key                  | Type   | Default value       |
| -------------------- | ------ | ------------------- |
| CheckpointBufferTime | uint64 | 1000 \* time.Second |

#### CLI commands <a href="#cli-commands" id="cli-commands"></a>

Commands are available for various actions such as sending checkpoints, sending `ack` or `no-ack` transactions, and querying parameters.

#### Printing all parameters <a href="#printing-all-parameters" id="printing-all-parameters"></a>

```
heimdallcli query checkpoint params --trust-node
```

Expected Result:

```
checkpoint_buffer_time: 16m40s
```

#### Send Checkpoint <a href="#send-checkpoint" id="send-checkpoint"></a>

Following command sends checkpoint transaction on Heimdall:

```
heimdallcli tx checkpoint send-checkpoint \
 --start-block=<start-block> \
 --end-block=<end-block> \
 --root-hash=<root-hash> \
 --account-root-hash=<account-root-hash> \
 --chain-id=<chain-id>
```

#### Send `ack` <a href="#send-ack" id="send-ack"></a>

Following command sends ack transaction on Heimdall if checkpoint is successful on Polygon:

```
heimdallcli tx checkpoint send-ack \
 --tx-hash=<checkpoint-tx-hash>
 --log-index=<checkpoint-event-log-index>
 --header=<checkpoint-index> \
  --chain-id=<chain-id>
```

#### Send `no-ack` <a href="#send-no-ack" id="send-no-ack"></a>

Following command send no-ack transaction on Heimdall:

```
heimdallcli tx checkpoint send-noack --chain-id <chain-id>
```

### REST APIs <a href="#rest-apis" id="rest-apis"></a>

Heimdall provides several REST APIs for interacting with the checkpoint module, including endpoints for preparing messages, querying checkpoints, and more.

| Name                                                                          | Method | Endpoint                          |
| ----------------------------------------------------------------------------- | ------ | --------------------------------- |
| It returns the prepared msg for ack checkpoint                                | POST   | /checkpoint/ack                   |
| It returns the prepared msg for new checkpoint                                | POST   | /checkpoint/new                   |
| It returns the prepared msg for no-ack checkpoint                             | POST   | /checkpoint/no-ack                |
| Checkpoint by number                                                          | GET    | /checkpoints/\<checkpoint-number> |
| Get current checkpoint buffer state                                           | GET    | /checkpoints/buffer               |
| Get checkpoint counts                                                         | GET    | /checkpoints/count                |
| Get last no-ack details                                                       | GET    | /checkpoints/last-no-ack          |
| Get latest checkpoint                                                         | GET    | /checkpoints/latest               |
| All checkpoints                                                               | GET    | /checkpoints/list                 |
| It returns the checkpoint parameters                                          | GET    | /checkpoints/parama               |
| It returns the prepared checkpoint                                            | GET    | /checkpoints/prepare              |
| Get ack count, buffer, validator set, validator count and last-no-ack details | GET    | /overview                         |

For more details and the response format of these APIs, visit Heimdall API Documentation.

## Topup

Topups are amounts used to pay fees on the Heimdall chain.

There are two ways to topup your account:

1. When new validator joins, they can mention a `topup` amount as top-up in addition to the staked amount, which will be moved as balance on Heimdall chain to pays fees on Heimdall.
2. A user can directly call the top-up function on the staking smart contract on Polygon to increase top-up balance on Heimdall.

### Messages <a href="#messages" id="messages"></a>

#### MsgTopup <a href="#msgtopup" id="msgtopup"></a>

`MsgTopup` transaction is responsible for minting balance to an address on Heimdall based on Polygon chain’s `TopUpEvent` on staking manager contract.

Handler for this transaction processes top-up and increases the balance only once for any given `msg.TxHash` and `msg.LogIndex`. It throws `Older invalid tx found` error, if trying to process the top-up more than once.

Here is the structure for the top-up transaction message:

```
type MsgTopup struct {
 FromAddress types.HeimdallAddress `json:"from_address"`
 ID          types.ValidatorID     `json:"id"`
 TxHash      types.HeimdallHash    `json:"tx_hash"`
 LogIndex    uint64                `json:"log_index"`
}
```

#### MsgWithdrawFee <a href="#msgwithdrawfee" id="msgwithdrawfee"></a>

`MsgWithdrawFee` transaction is responsible for withdrawing balance from Heimdall to Polygon chain. A Validator can withdraw any amount from Heimdall.

Handler processes the withdraw by deducting the balance from the given validator and prepares the state to send the next checkpoint. The next possible checkpoint will contain the withdraw related state for the specific validator.

Handler gets validator information based on `ValidatorAddress` and processes the withdraw.

```
// MsgWithdrawFee - high-level transaction of the fee coin withdrawal module
type MsgWithdrawFee struct {
 ValidatorAddress types.HeimdallAddress `json:"from_address"`
 Amount           types.Int             `json:"amount"`
}
```

### CLI Commands <a href="#cli-commands" id="cli-commands"></a>

#### Topup fee <a href="#topup-fee" id="topup-fee"></a>

```
heimdallcli tx topup fee
 --log-index <log-index> 
 --tx-hash <transaction-hash> 
 --validator-id <validator ID here>
 --chain-id <heimdall-chain-id>
```

#### Withdraw fee <a href="#withdraw-fee" id="withdraw-fee"></a>

```
heimdallcli tx topup withdraw --chain-id <heimdall-chain-id>
```

To check reflected topup on account run following command

```
heimdallcli query auth account <validator-address> --trust-node
```

### REST APIs <a href="#rest-apis" id="rest-apis"></a>

| Name         | Method | URL             | Body Params                                                                                                                                             |
| ------------ | ------ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Topup Fee    | POST   | /topup/fee      | `id` Validator id, `tx_hash` Transaction hash of successful topup event on Polygon chain, `log_index` Log index of topup event emitted on Polygon chain |
| Withdraw Fee | POST   | /topup/withdraw | `amount` Withdraw amount                                                                                                                                |

## Chain management

This document specifies an overview of the chain manager module of Heimdall.

The **chain manager** module provides all necessary dependencies like `contract-addresses`, `bor_chain_id,` and `tx_confirmation_time`. Other parameters can be added to this later on.

Params are updated through the `gov` module.

### Types <a href="#types" id="types"></a>

Chainmanager structure on Heimdall looks like the following:

```
type ChainParams struct {
 // BorChainID is valid bor chainId
 BorChainID            string                  `json:"bor_chain_id" yaml:"bor_chain_id"`

 // StakingManagerAddress is valid contract address
 StakingManagerAddress hmTypes.HeimdallAddress `json:"staking_manager_address" yaml:"staking_manager_address"`

 // RootChainAddress is valid contract address
 RootChainAddress      hmTypes.HeimdallAddress `json:"root_chain_address" yaml:"root_chain_address"`

 // StakingInfoAddress is valid contract address
 StakingInfoAddress    hmTypes.HeimdallAddress `json:"staking_info_address" yaml:"staking_info_address"`

 // StateSendedAddress is valid contract address
 StateSenderAddress    hmTypes.HeimdallAddress `json:"state_sender_address" yaml:"state_sender_address"`

 // Bor Chain Contracts
 // StateReceiveAddress is valid contract address
 StateReceiverAddress hmTypes.HeimdallAddress `json:"state_receiver_address" yaml:"state_receiver_address"`

 // ValidatorSetAddress is valid contract address
 ValidatorSetAddress  hmTypes.HeimdallAddress `json:"validator_set_address" yaml:"validator_set_address"`
}
```

### CLI commands <a href="#cli-commands" id="cli-commands"></a>

#### Parameters <a href="#parameters" id="parameters"></a>

To print all params;

```
heimdallcli query chainmanager params --trust-node
```

#### Expected result <a href="#expected-result" id="expected-result"></a>

```
tx_confirmation_time: 12s
chain_params:
  bor_chain_id: "1370"
  rama_token_address: "0x0000000000000000000000000000000000000000"
  staking_manager_address: "0x0000000000000000000000000000000000000000"
  root_chain_address: "0x0000000000000000000000000000000000000000"
  staking_info_address: "0x0000000000000000000000000000000000000000"
  state_sender_address: "0x0000000000000000000000000000000000000000"
  state_receiver_address: "0x0000000000000000000000000000000000000000"
  validator_set_address: "0x0000000000000000000000000000000000000000"
```

#### REST APIs <a href="#rest-apis" id="rest-apis"></a>

| Name   | Method | URL                 |
| ------ | ------ | ------------------- |
| Params | GET    | chainmanager/params |

All query APIs will provide response in the following format:

```
{
 "height": "1",
 "result": {
  ...   
 }
}
```

## Governance

Heimdall’s governance operates identically to the Cosmos-sdk `x/gov` module, as detailed in [Cosmos-sdk documentation](https://docs.cosmos.network/main/build/modules/gov).

### Overview <a href="#overview" id="overview"></a>

In Heimdall, token holders can influence decisions by voting on proposals. Each token equals one vote. The governance system currently supports:

* **Proposal submission:** Validators can submit proposals along with a deposit. If the deposit reaches the minimum threshold within a set period, the proposal moves to a voting phase. Validators can reclaim their deposits after the proposal’s acceptance or rejection.
* **Voting:** Validators are eligible to vote on proposals that have met the minimum deposit requirement.

The governance module includes two critical periods: the deposit and voting periods. Proposals failing to meet the minimum deposit by the end of the deposit period are automatically rejected. Upon reaching the minimum deposit, the voting period commences, during which validators cast their votes. After the voting period, the `gov/Endblocker.go` script tallies the votes and determines the proposal’s fate based on `tally_params`: quorum, threshold, and veto. The tallying process is detailed in the source code at Heimdall GitHub repository.

#### Types of proposals <a href="#types-of-proposals" id="types-of-proposals"></a>

Currently, Heimdall supports the **Param Change Proposal**, allowing validators to modify parameters in any of Heimdall’s modules.

**Param Change Proposal example**

For instance, validators might propose to alter the minimum `tx_fees` in the `auth` module. If the proposal is approved, the parameters in the Heimdall state are automatically updated without the need for an additional transaction.

### Command Line Interface (CLI) commands <a href="#command-line-interface-cli-commands" id="command-line-interface-cli-commands"></a>

#### Checking governance parameters <a href="#checking-governance-parameters" id="checking-governance-parameters"></a>

To view all parameters for the governance module:

```
heimdallcli query gov params --trust-node
```

This command displays the current governance parameters, such as voting period, quorum, threshold, veto, and minimum deposit requirements.

#### Submitting a proposal <a href="#submitting-a-proposal" id="submitting-a-proposal"></a>

To submit a proposal:

```
heimdallcli tx gov submit-proposal \
 --validator-id 1 param-change proposal.json \
 --chain-id <heimdall-chain-id>
```

`proposal.json` is a JSON-formatted file containing the proposal details.

#### Querying proposals <a href="#querying-proposals" id="querying-proposals"></a>

To list all proposals:

```
heimdallcli query gov proposals --trust-node
```

To query a specific proposal:

```
heimdallcli query gov proposal 1 --trust-node
```

#### Voting on a proposal <a href="#voting-on-a-proposal" id="voting-on-a-proposal"></a>

To vote on a proposal:

```
heimdallcli tx gov vote 1 "Yes" --validator-id 1 --chain-id <heimdall-chain-id>
```

Votes are automatically tallied after the voting period concludes.

### REST APIs <a href="#rest-apis" id="rest-apis"></a>

Heimdall also offers REST APIs for interacting with the governance system:

| Name                         | Method | Endpoint                             |
| ---------------------------- | ------ | ------------------------------------ |
| Get all proposals            | GET    | `/gov/proposals`                     |
| Get proposal details         | GET    | `/gov/proposals/{proposal-id}`       |
| Get all votes for a proposal | GET    | `/gov/proposals/{proposal-id}/votes` |

These APIs facilitate access to proposal details, voting records, and overall governance activity.
