github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/sdk/javascript/processor/context.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 {
    21    TpStateEntry,
    22    TpStateGetRequest,
    23    TpStateGetResponse,
    24    TpStateSetRequest,
    25    TpStateSetResponse,
    26    TpStateDeleteRequest,
    27    TpStateDeleteResponse,
    28    TpReceiptAddDataRequest,
    29    TpReceiptAddDataResponse,
    30    Event,
    31    TpEventAddRequest,
    32    TpEventAddResponse,
    33    Message
    34  } = require('../protobuf')
    35  
    36  const {
    37    AuthorizationException,
    38    InternalError
    39  } = require('../processor/exceptions')
    40  
    41  const _timeoutPromise = (p, millis) => {
    42    if (millis !== null && millis !== undefined) {
    43      return Promise.race([
    44        new Promise(
    45          (resolve, reject) =>
    46            setTimeout(() => reject(Error('Timeout occurred')), millis)
    47        ),
    48        p
    49      ])
    50    } else {
    51      return p
    52    }
    53  }
    54  
    55  /**
    56   * Context provides an interface for getting and setting validator
    57   * state. All validator interactions by a handler should be through
    58   * a Context instance.
    59   */
    60  class Context {
    61    constructor (stream, contextId) {
    62      this._stream = stream
    63      this._contextId = contextId
    64    }
    65  
    66    /**
    67     * getState queries the validator state for data at each of the
    68     * addresses in the given list. The addresses that have been set are
    69     * returned in a list.
    70     *
    71     * @param {string[]} addresses an array of addresses
    72     * @param {number} [timeout] - an optional timeout
    73     * @return a promise for a map of (address, buffer) pairs, where the
    74     * buffer is the encoded value at the specified address
    75     * @throws {AuthorizationException}
    76     */
    77    getState (addresses, timeout = null) {
    78      let getRequest = TpStateGetRequest.create({
    79        addresses,
    80        contextId: this._contextId
    81      })
    82      let future = this._stream.send(
    83        Message.MessageType.TP_STATE_GET_REQUEST,
    84        TpStateGetRequest.encode(getRequest).finish()
    85      )
    86      return _timeoutPromise(
    87        future.then(buffer => {
    88          let getResponse = TpStateGetResponse.decode(buffer)
    89  
    90          let results = {}
    91          getResponse.entries.forEach(entry => {
    92            results[entry.address] = entry.data
    93          })
    94          if (
    95            getResponse.status === TpStateGetResponse.Status.AUTHORIZATION_ERROR
    96          ) {
    97            throw new AuthorizationException(
    98              `Tried to get unauthorized address ${addresses}`
    99            )
   100          }
   101          return results
   102        }),
   103        timeout)
   104    }
   105  
   106    /**
   107     * setState requests that each address in the provided dictionary
   108     * be set in validator state to its corresponding value. A list is
   109     * returned containing the successfully set addresses.
   110  
   111     * @param {Object} addressValuePairs - a map of (address, buffer)
   112     * entries, where the buffer is the encoded value to be set at the
   113     * the given address.
   114     * @param {number} [timeout] - an optional timeout
   115     * @return a promise for the adddresses successfully set.
   116     * @throws {AuthorizationException}
   117     */
   118    setState (addressValuePairs, timeout = null) {
   119      let entries = Object.keys(addressValuePairs).map((address) =>
   120        TpStateEntry.create({address, data: addressValuePairs[address]}))
   121  
   122      let setRequest = TpStateSetRequest.create({
   123        entries,
   124        contextId: this._contextId
   125      })
   126      let future = this._stream.send(
   127        Message.MessageType.TP_STATE_SET_REQUEST,
   128        TpStateSetRequest.encode(setRequest).finish()
   129      )
   130  
   131      return _timeoutPromise(
   132        future.then((buffer) => {
   133          let setResponse = TpStateSetResponse.decode(buffer)
   134          if (setResponse.status === TpStateSetResponse.Status.AUTHORIZATION_ERROR) {
   135            let addresses = Object.keys(addressValuePairs)
   136            throw new AuthorizationException(
   137              `Tried to set unauthorized address ${addresses}`
   138            )
   139          }
   140          return setResponse.addresses
   141        }),
   142        timeout)
   143    }
   144  
   145    /**
   146     * deleteState requests that each of the provided addresses be
   147     * unset in validator state. A list of successfully deleted
   148     * addresses is returned.
   149     *
   150     * @param {string[]} addresses -  an array of addresses
   151     * @param {number} [timeout] - an optional timeout
   152     * @return a promise for the adddresses successfully deleted.
   153     * @throws {AuthorizationException}
   154     */
   155    deleteState (addresses, timeout = null) {
   156      let getRequest = TpStateDeleteRequest.create({
   157        addresses,
   158        contextId: this._contextId
   159      })
   160      let future = this._stream.send(
   161        Message.MessageType.TP_STATE_DELETE_REQUEST,
   162        TpStateDeleteRequest.encode(getRequest).finish()
   163      )
   164      return _timeoutPromise(
   165        future.then((buffer) => {
   166          let deleteResponse = TpStateDeleteResponse.decode(buffer)
   167  
   168          if (
   169            deleteResponse.status ===
   170            TpStateDeleteResponse.Status.AUTHORIZATION_ERROR
   171          ) {
   172            throw new AuthorizationException(
   173              `Tried to delete unauthorized address ${addresses}`
   174            )
   175          }
   176          return deleteResponse.addresses
   177        }),
   178        timeout)
   179    }
   180  
   181    /**
   182     * Add a blob to the execution result for this transaction.
   183     *
   184     * @param {Buffer} data - the data to add
   185     * @param {number} [timeout] - an optional timeout
   186     * @return {Promise} a promise that resolves to nothing on success, or an
   187     * error if the operation fails
   188     */
   189    addReceiptData (data, timeout = null) {
   190      let addReceiptRequest = TpReceiptAddDataRequest.create({
   191        contextId: this._contextId,
   192        data
   193      })
   194  
   195      let future = this._stream.send(
   196        Message.MessageType.TP_RECEIPT_ADD_DATA_REQUEST,
   197        TpReceiptAddDataRequest.encode(addReceiptRequest).finish()
   198      )
   199  
   200      return _timeoutPromise(
   201        future.then((buffer) => {
   202          let response = TpReceiptAddDataResponse.decode(buffer)
   203  
   204          if (response.status !== TpReceiptAddDataResponse.Status.OK) {
   205            throw new InternalError('Failed to add receipt data')
   206          }
   207        }),
   208        timeout)
   209    }
   210  
   211    /**
   212     * Add a new event to the execution result for this transaction.
   213     *
   214     * @param {string} eventType - This is used to subscribe to events. It should
   215     * be globally unique and describe what, in general, has occurred
   216     * @param {string[][]} attributes - Additional information about the event that
   217     * is transparent to the validator.  Attributes can be used by subscribers to
   218     * filter the type of events they receive.
   219     * @param {Buffer} data - Additional information about the event that is
   220     * opaque to the validator.
   221     * @param {number} [timeout] - an optional timeout
   222     * @return {Promise} a promise that resolves to nothing on success, or an
   223     * error if the operation fails
   224     */
   225    addEvent (eventType, attributes, data, timeout = null) {
   226      if (attributes === null || attributes === undefined) {
   227        attributes = []
   228      }
   229  
   230      let event = Event.create({
   231        eventType,
   232        attributes: attributes.map(
   233          ([ key, value ]) => Event.Attribute.create({ key, value })
   234        ),
   235        data
   236      })
   237  
   238      let request = TpEventAddRequest.encode({
   239        contextId: this._contextId,
   240        event
   241      }).finish()
   242  
   243      let future = this._stream.send(
   244        Message.MessageType.TP_EVENT_ADD_REQUEST,
   245        request
   246      )
   247  
   248      return _timeoutPromise(
   249        future.then((buffer) => {
   250          let response = TpEventAddResponse.decode(buffer)
   251  
   252          if (response.status !== TpEventAddResponse.Status.OK) {
   253            throw new InternalError(`Failed to add event: ${eventType}`)
   254          }
   255        }),
   256        timeout)
   257    }
   258  }
   259  
   260  module.exports = Context