# All files / src/txHelpers submitPeriod.js

89.8% Statements 44/49
77.27% Branches 17/22
100% Functions 5/5
89.13% Lines 41/46

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120

    1x
    1x
    1x

    1x

    1x
    7x
    7x
    7x

    1x
    6x

    6x
    5x
    1x

    1x
    8x
    8x
    8x

    8x

    8x

    8x
    1x

    1x
    1x

    7x
    7x

    7x
    6x

    6x

    6x

    6x

    6x
    2x

    2x

    4x

    4x

    4x

    4x
    4x
    4x
    4x

    5x

     /**
     * Copyright (c) 2018-present, Leap DAO (leapdao.org)
     *
     * This source code is licensed under the Mozilla Public License Version 2.0
     * found in the LICENSE file in the root directory of this source tree.
     */

    const {
      getSlotsByAddr,
      sendTransaction,
      getCurrentSlotId,
      GENESIS,
      buildCas,
    } = require('../utils');
    const { logPeriod } = require('../utils/debug');
    const checkEnoughVotes = require('../period/utils/checkEnoughVotes');

    const inFlight = {};

    /* istanbul ignore next */
    const logError = height => err => {
      logPeriod('submitPeriod error: %s (height: %d)', err.message, height);
    };

    const mySlotToSubmitFor = (slots, height, mySlots) => {
      const currentSlotId = getCurrentSlotId(slots, height);
      logPeriod('mySlots', currentSlotId, mySlots);
      return mySlots.find(slot => slot.id === currentSlotId);
    };

    const getPrevPeriodRoot = (period, bridgeState) => {
      const { lastBlocksRoot, lastPeriodRoot } = bridgeState;

      if (!lastBlocksRoot) return GENESIS; // not submissions yet = first period to be submitted
      if (lastBlocksRoot === period.prevHash) return lastPeriodRoot; // found
      return null; // not found
    };

    module.exports = async (period, slots, height, bridgeState) => {
      const { lastBlocksRoot, lastPeriodRoot } = bridgeState;
      const periodVotes = bridgeState.currentState.periodVotes || {};
      const periodRoot = period.merkleRoot();

      let submittedPeriod = { timestamp: '0' };

      Iif (inFlight[periodRoot]) {
        logPeriod('submittedPeriod in flight', periodRoot);
        return submittedPeriod;
      }

      if (lastBlocksRoot === periodRoot) {
        submittedPeriod = await bridgeState.bridgeContract.methods
          .periods(lastPeriodRoot)
          .call();
        logPeriod('submittedPeriod', periodRoot, submittedPeriod);
        return submittedPeriod;
      }

      const mySlots = getSlotsByAddr(slots, bridgeState.account.address);
      const mySlotToSubmit = mySlotToSubmitFor(slots, height, mySlots);

      if (mySlotToSubmit) {
        logPeriod('submitPeriod. Slot %d', mySlotToSubmit.id);

        // always try to use the last submitted one
        const prevPeriodRoot =
          getPrevPeriodRoot(period, bridgeState) || lastPeriodRoot;

        Iif (!prevPeriodRoot) {
          logPeriod(
            'submitPeriod. Not previous period root found. Skipping submission'
          );
          return submittedPeriod;
        }

        const { result, votes, needed } = checkEnoughVotes(
          periodRoot,
          bridgeState.currentState
        );

        if (!result) {
          logPeriod(
            `submitPeriod. Not enough period votes collected: ${votes}/${needed}. Waiting..`
          );
          return submittedPeriod;
        }

        const cas = buildCas(periodVotes[periodRoot]);

        inFlight[periodRoot] = true;

        const tx = sendTransaction(
          bridgeState.web3,
          bridgeState.operatorContract.methods.submitPeriodWithCas(
            mySlotToSubmit.id,
            prevPeriodRoot,
            periodRoot,
            `0x${cas.toString(16)}`
          ),
          bridgeState.operatorContract.options.address,
          bridgeState.account
        ).catch(
          /* istanbul ignore next */ () => {
            delete inFlight[periodRoot];
            logError(height);
          }
        );

        tx.then(receipt => {
          logPeriod('submitPeriod tx', receipt);
          delete inFlight[periodRoot];
          Iif (receipt && receipt.status === 1) {
            bridgeState.submittedPeriod[periodRoot] = true;
          }
        });
      }

      return submittedPeriod;
    };