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