Better input validation

This commit is contained in:
Kagami Hiiragi 2015-01-11 05:59:32 +03:00
parent 12066842cc
commit e3765b81fc
4 changed files with 42 additions and 34 deletions

View File

@ -56,14 +56,14 @@ exports.pow = function(opts) {
// Check all input params prematurely to not let promise executor or
// worker to fail because of it.
// 1 - UINT32_MAX
assert(poolSize > 0, "Pool size is too low");
assert(poolSize <= 4294967295, "Pool size is too high");
// 0 - (2^53 - 1)
assert(typeof poolSize === "number", "Bad pool size");
assert(poolSize >= 1, "Pool size is too low");
assert(poolSize <= 1024, "Pool size is too high");
assert(typeof opts.target === "number", "Bad target");
assert(opts.target >= 0, "Target is too low");
assert(opts.target <= 9007199254740991, "Target is too high");
assert(Buffer.isBuffer(opts.initialHash), "Bad initial hash");
assert(opts.initialHash.length === 64, "Bad initial hash");
// TODO(Kagami): Allow to cancel a POW (see `platform.browser.js`).
return new promise(function(resolve, reject) {

View File

@ -9,15 +9,15 @@
#include <pthread.h>
#include <arpa/inet.h>
#include <openssl/sha.h>
#include "./pow.h"
#define HASH_SIZE 64
typedef enum {
RESULT_NOT_READY,
RESULT_OK,
RESULT_OVERFLOW,
RESULT_ERROR
} Result;
enum PowResult {
RESULT_OK = 0,
RESULT_OVERFLOW = -1,
RESULT_ERROR = -2,
RESULT_BAD_INPUT = -3,
RESULT_NOT_READY = -4
};
// Global arguments.
size_t g_pool_size;
@ -27,7 +27,7 @@ uint64_t g_max_nonce;
// Shared variables for threads.
pthread_mutex_t g_mutex;
Result g_result = RESULT_NOT_READY;
PowResult g_result = RESULT_NOT_READY;
uint64_t g_nonce;
inline uint64_t ntohll(uint64_t x) {
@ -38,7 +38,7 @@ inline uint64_t ntohll(uint64_t x) {
}
// Set POW computation result in a thread-safe way.
void set_result(Result res, uint64_t nonce) {
void set_result(PowResult res, uint64_t nonce) {
pthread_mutex_lock(&g_mutex);
if (g_result == RESULT_NOT_READY) {
g_result = res;
@ -87,6 +87,9 @@ int pow(size_t pool_size,
const uint8_t* initial_hash,
uint64_t max_nonce,
uint64_t* nonce) {
if (pool_size < 1 || pool_size > MAX_POOL_SIZE) {
return RESULT_BAD_INPUT;
}
g_pool_size = pool_size;
g_target = target;
g_initial_hash = (uint8_t *)initial_hash;
@ -112,18 +115,10 @@ int pow(size_t pool_size,
pthread_join(threads[i], NULL);
}
switch (g_result) {
case RESULT_OK:
*nonce = g_nonce;
error = 0;
break;
case RESULT_OVERFLOW:
error = -1;
break;
default:
error = -2;
if (g_result == RESULT_OK) {
*nonce = g_nonce;
}
pthread_mutex_destroy(&g_mutex);
return error;
return g_result;
}

View File

@ -1,6 +1,9 @@
#ifndef BITMESSAGE_POW_H
#define BITMESSAGE_POW_H
#define MAX_POOL_SIZE 1024
#define HASH_SIZE 64
int pow(size_t pool_size,
uint64_t target,
const uint8_t* initial_hash,

View File

@ -68,22 +68,32 @@ class PowWorker : public NanAsyncWorker {
NAN_METHOD(PowAsync) {
NanScope();
NanCallback *callback = new NanCallback(args[3].As<Function>());
if (args.Length() != 4 ||
!args[0]->IsNumber() || // pool_size
!args[1]->IsNumber() || // target
!args[2]->IsObject() || // initial_hash
!args[3]->IsFunction()) { // cb
NanThrowError("Bad input");
NanReturnUndefined();
}
size_t pool_size = args[0]->Uint32Value();
uint64_t target = args[1]->IntegerValue();
size_t length = Buffer::Length(args[2]->ToObject());
char* buf = Buffer::Data(args[2]->ToObject());
if (pool_size < 1 || pool_size > MAX_POOL_SIZE || length != HASH_SIZE) {
NanThrowError("Bad input");
NanReturnUndefined();
}
uint8_t* initial_hash = (uint8_t *)malloc(length);
if (initial_hash == NULL) {
Local<Value> argv[] = {NanError("Internal error")};
callback->Call(1, argv);
} else {
memcpy(initial_hash, buf, length);
NanAsyncQueueWorker(
new PowWorker(callback, pool_size, target, initial_hash));
NanThrowError("Internal error");
NanReturnUndefined();
}
char* buf = Buffer::Data(args[2]->ToObject());
memcpy(initial_hash, buf, length);
NanCallback* callback = new NanCallback(args[3].As<Function>());
NanAsyncQueueWorker(new PowWorker(callback, pool_size, target, initial_hash));
NanReturnUndefined();
}