diff --git a/common/random/random.go b/common/random/random.go new file mode 100644 index 0000000000000000000000000000000000000000..c066671fe7d97ec2fd245cb8f2d080820163275f --- /dev/null +++ b/common/random/random.go @@ -0,0 +1,155 @@ +// Copyright 2015-2017 Monax Industries Limited. +// This file is part of the Monax platform (Monax) + +// Monax is free software: you can use, redistribute it and/or modify +// it only under the terms of the GNU General Public License, version +// 3, as published by the Free Software Foundation. + +// Monax is distributed WITHOUT ANY WARRANTY pursuant to +// the terms of the Gnu General Public Licence, version 3, including +// (but not limited to) Clause 15 thereof. See the text of the +// GNU General Public License, version 3 for full terms. + +// You should have received a copy of the GNU General Public License, +// version 3, with Monax. If not, see <http://www.gnu.org/licenses/>. + +package random + +import ( + crand "crypto/rand" + "math/rand" + "time" + + "github.com/eris-ltd/eris-db/common/sanity" +) + +const ( + strChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // 62 characters +) + +func init() { + b := cRandBytes(8) + var seed uint64 + for i := 0; i < 8; i++ { + seed |= uint64(b[i]) + seed <<= 8 + } + rand.Seed(int64(seed)) +} + +// Constructs an alphanumeric string of given length. +func RandStr(length int) string { + chars := []byte{} +MAIN_LOOP: + for { + val := rand.Int63() + for i := 0; i < 10; i++ { + v := int(val & 0x3f) // rightmost 6 bits + if v >= 62 { // only 62 characters in strChars + val >>= 6 + continue + } else { + chars = append(chars, strChars[v]) + if len(chars) == length { + break MAIN_LOOP + } + val >>= 6 + } + } + } + + return string(chars) +} + +func RandUint16() uint16 { + return uint16(rand.Uint32() & (1<<16 - 1)) +} + +func RandUint32() uint32 { + return rand.Uint32() +} + +func RandUint64() uint64 { + return uint64(rand.Uint32())<<32 + uint64(rand.Uint32()) +} + +func RandUint() uint { + return uint(rand.Int()) +} + +func RandInt16() int16 { + return int16(rand.Uint32() & (1<<16 - 1)) +} + +func RandInt32() int32 { + return int32(rand.Uint32()) +} + +func RandInt64() int64 { + return int64(rand.Uint32())<<32 + int64(rand.Uint32()) +} + +func RandInt() int { + return rand.Int() +} + +// Distributed pseudo-exponentially to test for various cases +func RandUint16Exp() uint16 { + bits := rand.Uint32() % 16 + if bits == 0 { + return 0 + } + n := uint16(1 << (bits - 1)) + n += uint16(rand.Int31()) & ((1 << (bits - 1)) - 1) + return n +} + +// Distributed pseudo-exponentially to test for various cases +func RandUint32Exp() uint32 { + bits := rand.Uint32() % 32 + if bits == 0 { + return 0 + } + n := uint32(1 << (bits - 1)) + n += uint32(rand.Int31()) & ((1 << (bits - 1)) - 1) + return n +} + +// Distributed pseudo-exponentially to test for various cases +func RandUint64Exp() uint64 { + bits := rand.Uint32() % 64 + if bits == 0 { + return 0 + } + n := uint64(1 << (bits - 1)) + n += uint64(rand.Int63()) & ((1 << (bits - 1)) - 1) + return n +} + +func RandFloat32() float32 { + return rand.Float32() +} + +func RandTime() time.Time { + return time.Unix(int64(RandUint64Exp()), 0) +} + +func RandBytes(n int) []byte { + bs := make([]byte, n) + for i := 0; i < n; i++ { + bs[i] = byte(rand.Intn(256)) + } + return bs +} + +// NOTE: This relies on the os's random number generator. +// For real security, we should salt that with some seed. +// See github.com/tendermint/go-crypto for a more secure reader. +func cRandBytes(numBytes int) []byte { + b := make([]byte, numBytes) + _, err := crand.Read(b) + if err != nil { + sanity.PanicCrisis(err) + } + return b +} diff --git a/common/sanity/sanity.go b/common/sanity/sanity.go new file mode 100644 index 0000000000000000000000000000000000000000..264eeb7c754284f26ab85729febed39ede8f8d17 --- /dev/null +++ b/common/sanity/sanity.go @@ -0,0 +1,49 @@ +// Copyright 2015-2017 Monax Industries Limited. +// This file is part of the Monax platform (Monax) + +// Monax is free software: you can use, redistribute it and/or modify +// it only under the terms of the GNU General Public License, version +// 3, as published by the Free Software Foundation. + +// Monax is distributed WITHOUT ANY WARRANTY pursuant to +// the terms of the Gnu General Public Licence, version 3, including +// (but not limited to) Clause 15 thereof. See the text of the +// GNU General Public License, version 3 for full terms. + +// You should have received a copy of the GNU General Public License, +// version 3, with Monax. If not, see <http://www.gnu.org/licenses/>. + +package sanity + +import ( + "fmt" +) + +//-------------------------------------------------------------------------------------------------- +// panic wrappers +// NOTE: [ben] Fail fast and fail hard, these are wrappers that point to code that needs +// to be addressed, but simplify finding them in the code; + +// A panic resulting from a sanity check means there is a programmer error +// and some gaurantee is not satisfied. +func PanicSanity(v interface{}) { + panic(fmt.Sprintf("Paniced on a Sanity Check: %v", v)) +} + +// A panic here means something has gone horribly wrong, in the form of data corruption or +// failure of the operating system. In a correct/healthy system, these should never fire. +// If they do, it's indicative of a much more serious problem. +func PanicCrisis(v interface{}) { + panic(fmt.Sprintf("Paniced on a Crisis: %v", v)) +} + +// Indicates a failure of consensus. Someone was malicious or something has +// gone horribly wrong. These should really boot us into an "emergency-recover" mode +func PanicConsensus(v interface{}) { + panic(fmt.Sprintf("Paniced on a Consensus Failure: %v", v)) +} + +// For those times when we're not sure if we should panic +func PanicQ(v interface{}) { + panic(fmt.Sprintf("Paniced questionably: %v", v)) +}