github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/sdk/examples/intkey_javascript/integer_key_handler.js (about)

     1  /**
     2   * Copyright 2016 Intel Corporation
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   * ------------------------------------------------------------------------------
    16   */
    17  
    18  'use strict'
    19  
    20  const { TransactionHandler } = require('sawtooth-sdk/processor/handler')
    21  const {
    22    InvalidTransaction,
    23    InternalError
    24  } = require('sawtooth-sdk/processor/exceptions')
    25  
    26  const crypto = require('crypto')
    27  const cbor = require('cbor')
    28  
    29  // Constants defined in intkey specification
    30  const MIN_VALUE = 0
    31  const MAX_VALUE = 4294967295
    32  const MAX_NAME_LENGTH = 20
    33  
    34  const _hash = (x) =>
    35    crypto.createHash('sha512').update(x).digest('hex').toLowerCase()
    36  
    37  const INT_KEY_FAMILY = 'intkey'
    38  const INT_KEY_NAMESPACE = _hash(INT_KEY_FAMILY).substring(0, 6)
    39  
    40  const _decodeCbor = (buffer) =>
    41    new Promise((resolve, reject) =>
    42      cbor.decodeFirst(buffer, (err, obj) => (err ? reject(err) : resolve(obj)))
    43    )
    44  
    45  const _toInternalError = (err) => {
    46    let message = (err.message) ? err.message : err
    47    throw new InternalError(message)
    48  }
    49  
    50  const _setEntry = (context, address, stateValue) => {
    51    let entries = {
    52      [address]: cbor.encode(stateValue)
    53    }
    54    return context.setState(entries)
    55  }
    56  
    57  const _applySet = (context, address, name, value) => (possibleAddressValues) => {
    58    let stateValueRep = possibleAddressValues[address]
    59  
    60    let stateValue
    61    if (stateValueRep && stateValueRep.length > 0) {
    62      stateValue = cbor.decodeFirstSync(stateValueRep)
    63      let stateName = stateValue[name]
    64      if (stateName) {
    65        throw new InvalidTransaction(
    66          `Verb is "set" but Name already in state, Name: ${name} Value: ${stateName}`
    67        )
    68      }
    69    }
    70  
    71    // 'set' passes checks so store it in the state
    72    if (!stateValue) {
    73      stateValue = {}
    74    }
    75  
    76    stateValue[name] = value
    77  
    78    return _setEntry(context, address, stateValue)
    79  }
    80  
    81  const _applyOperator = (verb, op) => (context, address, name, value) => (possibleAddressValues) => {
    82    let stateValueRep = possibleAddressValues[address]
    83    if (!stateValueRep || stateValueRep.length === 0) {
    84      throw new InvalidTransaction(`Verb is ${verb} but Name is not in state`)
    85    }
    86  
    87    let stateValue = cbor.decodeFirstSync(stateValueRep)
    88    if (stateValue[name] === null || stateValue[name] === undefined) {
    89      throw new InvalidTransaction(`Verb is ${verb} but Name is not in state`)
    90    }
    91  
    92    const result = op(stateValue[name], value)
    93  
    94    if (result < MIN_VALUE) {
    95      throw new InvalidTransaction(
    96        `Verb is ${verb}, but result would be less than ${MIN_VALUE}`
    97      )
    98    }
    99  
   100    if (result > MAX_VALUE) {
   101      throw new InvalidTransaction(
   102        `Verb is ${verb}, but result would be greater than ${MAX_VALUE}`
   103      )
   104    }
   105  
   106    // Increment the value in state by value
   107    // stateValue[name] = op(stateValue[name], value)
   108    stateValue[name] = result
   109    return _setEntry(context, address, stateValue)
   110  }
   111  
   112  const _applyInc = _applyOperator('inc', (x, y) => x + y)
   113  const _applyDec = _applyOperator('dec', (x, y) => x - y)
   114  
   115  class IntegerKeyHandler extends TransactionHandler {
   116    constructor () {
   117      super(INT_KEY_FAMILY, ['1.0'], [INT_KEY_NAMESPACE])
   118    }
   119  
   120    apply (transactionProcessRequest, context) {
   121      return _decodeCbor(transactionProcessRequest.payload)
   122        .catch(_toInternalError)
   123        .then((update) => {
   124          //
   125          // Validate the update
   126          let name = update.Name
   127          if (!name) {
   128            throw new InvalidTransaction('Name is required')
   129          }
   130  
   131          if (name.length > MAX_NAME_LENGTH) {
   132            throw new InvalidTransaction(
   133              `Name must be a string of no more than ${MAX_NAME_LENGTH} characters`
   134            )
   135          }
   136  
   137          let verb = update.Verb
   138          if (!verb) {
   139            throw new InvalidTransaction('Verb is required')
   140          }
   141  
   142          let value = update.Value
   143          if (value === null || value === undefined) {
   144            throw new InvalidTransaction('Value is required')
   145          }
   146  
   147          let parsed = parseInt(value)
   148          if (parsed !== value || parsed < MIN_VALUE || parsed > MAX_VALUE) {
   149            throw new InvalidTransaction(
   150              `Value must be an integer ` +
   151              `no less than ${MIN_VALUE} and ` +
   152              `no greater than ${MAX_VALUE}`)
   153          }
   154  
   155          value = parsed
   156  
   157          // Determine the action to apply based on the verb
   158          let actionFn
   159          if (verb === 'set') {
   160            actionFn = _applySet
   161          } else if (verb === 'dec') {
   162            actionFn = _applyDec
   163          } else if (verb === 'inc') {
   164            actionFn = _applyInc
   165          } else {
   166            throw new InvalidTransaction(`Verb must be set, inc, dec not ${verb}`)
   167          }
   168  
   169          let address = INT_KEY_NAMESPACE + _hash(name).slice(-64)
   170  
   171          // Get the current state, for the key's address:
   172          let getPromise = context.getState([address])
   173  
   174          // Apply the action to the promise's result:
   175          let actionPromise = getPromise.then(
   176            actionFn(context, address, name, value)
   177          )
   178  
   179          // Validate that the action promise results in the correctly set address:
   180          return actionPromise.then(addresses => {
   181            if (addresses.length === 0) {
   182              throw new InternalError('State Error!')
   183            }
   184            console.log(`Verb: ${verb} Name: ${name} Value: ${value}`)
   185          })
   186        })
   187    }
   188  }
   189  
   190  module.exports = IntegerKeyHandler