skyfffire 2 lat temu
commit
083c3ae39d
69 zmienionych plików z 9158 dodań i 0 usunięć
  1. 5 0
      .dockerignore
  2. 52 0
      .gitignore
  3. 30 0
      common/big.go
  4. 188 0
      common/bitutil/bitutil.go
  5. 221 0
      common/bitutil/bitutil_test.go
  6. 170 0
      common/bitutil/compress.go
  7. 181 0
      common/bitutil/compress_test.go
  8. 139 0
      common/bytes.go
  9. 126 0
      common/bytes_test.go
  10. 65 0
      common/compiler/helpers.go
  11. 224 0
      common/compiler/solidity.go
  12. 78 0
      common/compiler/solidity_test.go
  13. 3 0
      common/compiler/test.v.py
  14. 3 0
      common/compiler/test_bad.v.py
  15. 144 0
      common/compiler/vyper.go
  16. 71 0
      common/compiler/vyper_test.go
  17. 52 0
      common/debug.go
  18. 67 0
      common/fdlimit/fdlimit_bsd.go
  19. 71 0
      common/fdlimit/fdlimit_darwin.go
  20. 45 0
      common/fdlimit/fdlimit_test.go
  21. 65 0
      common/fdlimit/fdlimit_unix.go
  22. 50 0
      common/fdlimit/fdlimit_windows.go
  23. 82 0
      common/format.go
  24. 59 0
      common/gopool/pool.go
  25. 240 0
      common/hexutil/hexutil.go
  26. 203 0
      common/hexutil/hexutil_test.go
  27. 376 0
      common/hexutil/json.go
  28. 45 0
      common/hexutil/json_example_test.go
  29. 374 0
      common/hexutil/json_test.go
  30. 259 0
      common/math/big.go
  31. 327 0
      common/math/big_test.go
  32. 98 0
      common/math/integer.go
  33. 116 0
      common/math/integer_test.go
  34. 127 0
      common/mclock/mclock.go
  35. 1 0
      common/mclock/mclock.s
  36. 209 0
      common/mclock/simclock.go
  37. 162 0
      common/mclock/simclock_test.go
  38. 49 0
      common/path.go
  39. 196 0
      common/prque/lazyqueue.go
  40. 124 0
      common/prque/lazyqueue_test.go
  41. 83 0
      common/prque/prque.go
  42. 130 0
      common/prque/prque_test.go
  43. 120 0
      common/prque/sstack.go
  44. 100 0
      common/prque/sstack_test.go
  45. 56 0
      common/size.go
  46. 38 0
      common/size_test.go
  47. 53 0
      common/test_utils.go
  48. 428 0
      common/types.go
  49. 539 0
      common/types_test.go
  50. 11 0
      go.mod
  51. 26 0
      go.sum
  52. 11 0
      log/CONTRIBUTORS
  53. 13 0
      log/LICENSE
  54. 77 0
      log/README.md
  55. 5 0
      log/README_ETHEREUM.md
  56. 214 0
      log/async_file_writer.go
  57. 26 0
      log/async_file_writer_test.go
  58. 333 0
      log/doc.go
  59. 486 0
      log/format.go
  60. 95 0
      log/format_test.go
  61. 375 0
      log/handler.go
  62. 232 0
      log/handler_glog.go
  63. 26 0
      log/handler_go13.go
  64. 23 0
      log/handler_go14.go
  65. 261 0
      log/logger.go
  66. 70 0
      log/root.go
  67. 57 0
      log/syslog.go
  68. 172 0
      p2p/config.go
  69. 1 0
      p2p/server.go

+ 5 - 0
.dockerignore

@@ -0,0 +1,5 @@
+**/*_test.go
+
+build/_workspace
+build/_bin
+tests/testdata

+ 52 - 0
.gitignore

@@ -0,0 +1,52 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+#   git config --global core.excludesfile ~/.gitignore_global
+
+/tmp
+*/**/*un~
+*/**/*.test
+*un~
+.DS_Store
+*/**/.DS_Store
+.ethtest
+*/**/*tx_database*
+*/**/*dapps*
+build/_vendor/pkg
+/tests/truffle/storage
+
+#*
+.#*
+*#
+*~
+.project
+.settings
+
+# used by the Makefile
+/build/_workspace/
+/build/cache/
+/build/bin/
+/geth*.zip
+
+# travis
+profile.tmp
+profile.cov
+
+# IdeaIDE
+.idea
+
+# VS Code
+.vscode
+
+# dashboard
+/dashboard/assets/flow-typed
+/dashboard/assets/node_modules
+/dashboard/assets/stats.json
+/dashboard/assets/bundle.js
+/dashboard/assets/bundle.js.map
+/dashboard/assets/package-lock.json
+
+**/yarn-error.log
+cmd/geth/node/
+cmd/geth/__debug_bin

+ 30 - 0
common/big.go

@@ -0,0 +1,30 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package common
+
+import "math/big"
+
+// Common big integers often used
+var (
+	Big1   = big.NewInt(1)
+	Big2   = big.NewInt(2)
+	Big3   = big.NewInt(3)
+	Big0   = big.NewInt(0)
+	Big32  = big.NewInt(32)
+	Big256 = big.NewInt(256)
+	Big257 = big.NewInt(257)
+)

+ 188 - 0
common/bitutil/bitutil.go

@@ -0,0 +1,188 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Adapted from: https://golang.org/src/crypto/cipher/xor.go
+
+// Package bitutil implements fast bitwise operations.
+package bitutil
+
+import (
+	"runtime"
+	"unsafe"
+)
+
+const wordSize = int(unsafe.Sizeof(uintptr(0)))
+const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x"
+
+// XORBytes xors the bytes in a and b. The destination is assumed to have enough
+// space. Returns the number of bytes xor'd.
+func XORBytes(dst, a, b []byte) int {
+	if supportsUnaligned {
+		return fastXORBytes(dst, a, b)
+	}
+	return safeXORBytes(dst, a, b)
+}
+
+// fastXORBytes xors in bulk. It only works on architectures that support
+// unaligned read/writes.
+func fastXORBytes(dst, a, b []byte) int {
+	n := len(a)
+	if len(b) < n {
+		n = len(b)
+	}
+	w := n / wordSize
+	if w > 0 {
+		dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+		aw := *(*[]uintptr)(unsafe.Pointer(&a))
+		bw := *(*[]uintptr)(unsafe.Pointer(&b))
+		for i := 0; i < w; i++ {
+			dw[i] = aw[i] ^ bw[i]
+		}
+	}
+	for i := n - n%wordSize; i < n; i++ {
+		dst[i] = a[i] ^ b[i]
+	}
+	return n
+}
+
+// safeXORBytes xors one by one. It works on all architectures, independent if
+// it supports unaligned read/writes or not.
+func safeXORBytes(dst, a, b []byte) int {
+	n := len(a)
+	if len(b) < n {
+		n = len(b)
+	}
+	for i := 0; i < n; i++ {
+		dst[i] = a[i] ^ b[i]
+	}
+	return n
+}
+
+// ANDBytes ands the bytes in a and b. The destination is assumed to have enough
+// space. Returns the number of bytes and'd.
+func ANDBytes(dst, a, b []byte) int {
+	if supportsUnaligned {
+		return fastANDBytes(dst, a, b)
+	}
+	return safeANDBytes(dst, a, b)
+}
+
+// fastANDBytes ands in bulk. It only works on architectures that support
+// unaligned read/writes.
+func fastANDBytes(dst, a, b []byte) int {
+	n := len(a)
+	if len(b) < n {
+		n = len(b)
+	}
+	w := n / wordSize
+	if w > 0 {
+		dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+		aw := *(*[]uintptr)(unsafe.Pointer(&a))
+		bw := *(*[]uintptr)(unsafe.Pointer(&b))
+		for i := 0; i < w; i++ {
+			dw[i] = aw[i] & bw[i]
+		}
+	}
+	for i := n - n%wordSize; i < n; i++ {
+		dst[i] = a[i] & b[i]
+	}
+	return n
+}
+
+// safeANDBytes ands one by one. It works on all architectures, independent if
+// it supports unaligned read/writes or not.
+func safeANDBytes(dst, a, b []byte) int {
+	n := len(a)
+	if len(b) < n {
+		n = len(b)
+	}
+	for i := 0; i < n; i++ {
+		dst[i] = a[i] & b[i]
+	}
+	return n
+}
+
+// ORBytes ors the bytes in a and b. The destination is assumed to have enough
+// space. Returns the number of bytes or'd.
+func ORBytes(dst, a, b []byte) int {
+	if supportsUnaligned {
+		return fastORBytes(dst, a, b)
+	}
+	return safeORBytes(dst, a, b)
+}
+
+// fastORBytes ors in bulk. It only works on architectures that support
+// unaligned read/writes.
+func fastORBytes(dst, a, b []byte) int {
+	n := len(a)
+	if len(b) < n {
+		n = len(b)
+	}
+	w := n / wordSize
+	if w > 0 {
+		dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+		aw := *(*[]uintptr)(unsafe.Pointer(&a))
+		bw := *(*[]uintptr)(unsafe.Pointer(&b))
+		for i := 0; i < w; i++ {
+			dw[i] = aw[i] | bw[i]
+		}
+	}
+	for i := n - n%wordSize; i < n; i++ {
+		dst[i] = a[i] | b[i]
+	}
+	return n
+}
+
+// safeORBytes ors one by one. It works on all architectures, independent if
+// it supports unaligned read/writes or not.
+func safeORBytes(dst, a, b []byte) int {
+	n := len(a)
+	if len(b) < n {
+		n = len(b)
+	}
+	for i := 0; i < n; i++ {
+		dst[i] = a[i] | b[i]
+	}
+	return n
+}
+
+// TestBytes tests whether any bit is set in the input byte slice.
+func TestBytes(p []byte) bool {
+	if supportsUnaligned {
+		return fastTestBytes(p)
+	}
+	return safeTestBytes(p)
+}
+
+// fastTestBytes tests for set bits in bulk. It only works on architectures that
+// support unaligned read/writes.
+func fastTestBytes(p []byte) bool {
+	n := len(p)
+	w := n / wordSize
+	if w > 0 {
+		pw := *(*[]uintptr)(unsafe.Pointer(&p))
+		for i := 0; i < w; i++ {
+			if pw[i] != 0 {
+				return true
+			}
+		}
+	}
+	for i := n - n%wordSize; i < n; i++ {
+		if p[i] != 0 {
+			return true
+		}
+	}
+	return false
+}
+
+// safeTestBytes tests for set bits one byte at a time. It works on all
+// architectures, independent if it supports unaligned read/writes or not.
+func safeTestBytes(p []byte) bool {
+	for i := 0; i < len(p); i++ {
+		if p[i] != 0 {
+			return true
+		}
+	}
+	return false
+}

+ 221 - 0
common/bitutil/bitutil_test.go

@@ -0,0 +1,221 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Adapted from: https://golang.org/src/crypto/cipher/xor_test.go
+
+package bitutil
+
+import (
+	"bytes"
+	"testing"
+)
+
+// Tests that bitwise XOR works for various alignments.
+func TestXOR(t *testing.T) {
+	for alignP := 0; alignP < 2; alignP++ {
+		for alignQ := 0; alignQ < 2; alignQ++ {
+			for alignD := 0; alignD < 2; alignD++ {
+				p := make([]byte, 1023)[alignP:]
+				q := make([]byte, 1023)[alignQ:]
+
+				for i := 0; i < len(p); i++ {
+					p[i] = byte(i)
+				}
+				for i := 0; i < len(q); i++ {
+					q[i] = byte(len(q) - i)
+				}
+				d1 := make([]byte, 1023+alignD)[alignD:]
+				d2 := make([]byte, 1023+alignD)[alignD:]
+
+				XORBytes(d1, p, q)
+				safeXORBytes(d2, p, q)
+				if !bytes.Equal(d1, d2) {
+					t.Error("not equal", d1, d2)
+				}
+			}
+		}
+	}
+}
+
+// Tests that bitwise AND works for various alignments.
+func TestAND(t *testing.T) {
+	for alignP := 0; alignP < 2; alignP++ {
+		for alignQ := 0; alignQ < 2; alignQ++ {
+			for alignD := 0; alignD < 2; alignD++ {
+				p := make([]byte, 1023)[alignP:]
+				q := make([]byte, 1023)[alignQ:]
+
+				for i := 0; i < len(p); i++ {
+					p[i] = byte(i)
+				}
+				for i := 0; i < len(q); i++ {
+					q[i] = byte(len(q) - i)
+				}
+				d1 := make([]byte, 1023+alignD)[alignD:]
+				d2 := make([]byte, 1023+alignD)[alignD:]
+
+				ANDBytes(d1, p, q)
+				safeANDBytes(d2, p, q)
+				if !bytes.Equal(d1, d2) {
+					t.Error("not equal")
+				}
+			}
+		}
+	}
+}
+
+// Tests that bitwise OR works for various alignments.
+func TestOR(t *testing.T) {
+	for alignP := 0; alignP < 2; alignP++ {
+		for alignQ := 0; alignQ < 2; alignQ++ {
+			for alignD := 0; alignD < 2; alignD++ {
+				p := make([]byte, 1023)[alignP:]
+				q := make([]byte, 1023)[alignQ:]
+
+				for i := 0; i < len(p); i++ {
+					p[i] = byte(i)
+				}
+				for i := 0; i < len(q); i++ {
+					q[i] = byte(len(q) - i)
+				}
+				d1 := make([]byte, 1023+alignD)[alignD:]
+				d2 := make([]byte, 1023+alignD)[alignD:]
+
+				ORBytes(d1, p, q)
+				safeORBytes(d2, p, q)
+				if !bytes.Equal(d1, d2) {
+					t.Error("not equal")
+				}
+			}
+		}
+	}
+}
+
+// Tests that bit testing works for various alignments.
+func TestTest(t *testing.T) {
+	for align := 0; align < 2; align++ {
+		// Test for bits set in the bulk part
+		p := make([]byte, 1023)[align:]
+		p[100] = 1
+
+		if TestBytes(p) != safeTestBytes(p) {
+			t.Error("not equal")
+		}
+		// Test for bits set in the tail part
+		q := make([]byte, 1023)[align:]
+		q[len(q)-1] = 1
+
+		if TestBytes(q) != safeTestBytes(q) {
+			t.Error("not equal")
+		}
+	}
+}
+
+// Benchmarks the potentially optimized XOR performance.
+func BenchmarkFastXOR1KB(b *testing.B) { benchmarkFastXOR(b, 1024) }
+func BenchmarkFastXOR2KB(b *testing.B) { benchmarkFastXOR(b, 2048) }
+func BenchmarkFastXOR4KB(b *testing.B) { benchmarkFastXOR(b, 4096) }
+
+func benchmarkFastXOR(b *testing.B, size int) {
+	p, q := make([]byte, size), make([]byte, size)
+
+	for i := 0; i < b.N; i++ {
+		XORBytes(p, p, q)
+	}
+}
+
+// Benchmarks the baseline XOR performance.
+func BenchmarkBaseXOR1KB(b *testing.B) { benchmarkBaseXOR(b, 1024) }
+func BenchmarkBaseXOR2KB(b *testing.B) { benchmarkBaseXOR(b, 2048) }
+func BenchmarkBaseXOR4KB(b *testing.B) { benchmarkBaseXOR(b, 4096) }
+
+func benchmarkBaseXOR(b *testing.B, size int) {
+	p, q := make([]byte, size), make([]byte, size)
+
+	for i := 0; i < b.N; i++ {
+		safeXORBytes(p, p, q)
+	}
+}
+
+// Benchmarks the potentially optimized AND performance.
+func BenchmarkFastAND1KB(b *testing.B) { benchmarkFastAND(b, 1024) }
+func BenchmarkFastAND2KB(b *testing.B) { benchmarkFastAND(b, 2048) }
+func BenchmarkFastAND4KB(b *testing.B) { benchmarkFastAND(b, 4096) }
+
+func benchmarkFastAND(b *testing.B, size int) {
+	p, q := make([]byte, size), make([]byte, size)
+
+	for i := 0; i < b.N; i++ {
+		ANDBytes(p, p, q)
+	}
+}
+
+// Benchmarks the baseline AND performance.
+func BenchmarkBaseAND1KB(b *testing.B) { benchmarkBaseAND(b, 1024) }
+func BenchmarkBaseAND2KB(b *testing.B) { benchmarkBaseAND(b, 2048) }
+func BenchmarkBaseAND4KB(b *testing.B) { benchmarkBaseAND(b, 4096) }
+
+func benchmarkBaseAND(b *testing.B, size int) {
+	p, q := make([]byte, size), make([]byte, size)
+
+	for i := 0; i < b.N; i++ {
+		safeANDBytes(p, p, q)
+	}
+}
+
+// Benchmarks the potentially optimized OR performance.
+func BenchmarkFastOR1KB(b *testing.B) { benchmarkFastOR(b, 1024) }
+func BenchmarkFastOR2KB(b *testing.B) { benchmarkFastOR(b, 2048) }
+func BenchmarkFastOR4KB(b *testing.B) { benchmarkFastOR(b, 4096) }
+
+func benchmarkFastOR(b *testing.B, size int) {
+	p, q := make([]byte, size), make([]byte, size)
+
+	for i := 0; i < b.N; i++ {
+		ORBytes(p, p, q)
+	}
+}
+
+// Benchmarks the baseline OR performance.
+func BenchmarkBaseOR1KB(b *testing.B) { benchmarkBaseOR(b, 1024) }
+func BenchmarkBaseOR2KB(b *testing.B) { benchmarkBaseOR(b, 2048) }
+func BenchmarkBaseOR4KB(b *testing.B) { benchmarkBaseOR(b, 4096) }
+
+func benchmarkBaseOR(b *testing.B, size int) {
+	p, q := make([]byte, size), make([]byte, size)
+
+	for i := 0; i < b.N; i++ {
+		safeORBytes(p, p, q)
+	}
+}
+
+var GloBool bool // Exported global will not be dead-code eliminated, at least not yet.
+
+// Benchmarks the potentially optimized bit testing performance.
+func BenchmarkFastTest1KB(b *testing.B) { benchmarkFastTest(b, 1024) }
+func BenchmarkFastTest2KB(b *testing.B) { benchmarkFastTest(b, 2048) }
+func BenchmarkFastTest4KB(b *testing.B) { benchmarkFastTest(b, 4096) }
+
+func benchmarkFastTest(b *testing.B, size int) {
+	p := make([]byte, size)
+	a := false
+	for i := 0; i < b.N; i++ {
+		a = a != TestBytes(p)
+	}
+	GloBool = a // Use of benchmark "result" to prevent total dead code elimination.
+}
+
+// Benchmarks the baseline bit testing performance.
+func BenchmarkBaseTest1KB(b *testing.B) { benchmarkBaseTest(b, 1024) }
+func BenchmarkBaseTest2KB(b *testing.B) { benchmarkBaseTest(b, 2048) }
+func BenchmarkBaseTest4KB(b *testing.B) { benchmarkBaseTest(b, 4096) }
+
+func benchmarkBaseTest(b *testing.B, size int) {
+	p := make([]byte, size)
+	a := false
+	for i := 0; i < b.N; i++ {
+		a = a != safeTestBytes(p)
+	}
+	GloBool = a // Use of benchmark "result" to prevent total dead code elimination.
+}

+ 170 - 0
common/bitutil/compress.go

@@ -0,0 +1,170 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package bitutil
+
+import "errors"
+
+var (
+	// errMissingData is returned from decompression if the byte referenced by
+	// the bitset header overflows the input data.
+	errMissingData = errors.New("missing bytes on input")
+
+	// errUnreferencedData is returned from decompression if not all bytes were used
+	// up from the input data after decompressing it.
+	errUnreferencedData = errors.New("extra bytes on input")
+
+	// errExceededTarget is returned from decompression if the bitset header has
+	// more bits defined than the number of target buffer space available.
+	errExceededTarget = errors.New("target data size exceeded")
+
+	// errZeroContent is returned from decompression if a data byte referenced in
+	// the bitset header is actually a zero byte.
+	errZeroContent = errors.New("zero byte in input content")
+)
+
+// The compression algorithm implemented by CompressBytes and DecompressBytes is
+// optimized for sparse input data which contains a lot of zero bytes. Decompression
+// requires knowledge of the decompressed data length.
+//
+// Compression works as follows:
+//
+//   if data only contains zeroes,
+//       CompressBytes(data) == nil
+//   otherwise if len(data) <= 1,
+//       CompressBytes(data) == data
+//   otherwise:
+//       CompressBytes(data) == append(CompressBytes(nonZeroBitset(data)), nonZeroBytes(data)...)
+//       where
+//         nonZeroBitset(data) is a bit vector with len(data) bits (MSB first):
+//             nonZeroBitset(data)[i/8] && (1 << (7-i%8)) != 0  if data[i] != 0
+//             len(nonZeroBitset(data)) == (len(data)+7)/8
+//         nonZeroBytes(data) contains the non-zero bytes of data in the same order
+
+// CompressBytes compresses the input byte slice according to the sparse bitset
+// representation algorithm. If the result is bigger than the original input, no
+// compression is done.
+func CompressBytes(data []byte) []byte {
+	if out := bitsetEncodeBytes(data); len(out) < len(data) {
+		return out
+	}
+	cpy := make([]byte, len(data))
+	copy(cpy, data)
+	return cpy
+}
+
+// bitsetEncodeBytes compresses the input byte slice according to the sparse
+// bitset representation algorithm.
+func bitsetEncodeBytes(data []byte) []byte {
+	// Empty slices get compressed to nil
+	if len(data) == 0 {
+		return nil
+	}
+	// One byte slices compress to nil or retain the single byte
+	if len(data) == 1 {
+		if data[0] == 0 {
+			return nil
+		}
+		return data
+	}
+	// Calculate the bitset of set bytes, and gather the non-zero bytes
+	nonZeroBitset := make([]byte, (len(data)+7)/8)
+	nonZeroBytes := make([]byte, 0, len(data))
+
+	for i, b := range data {
+		if b != 0 {
+			nonZeroBytes = append(nonZeroBytes, b)
+			nonZeroBitset[i/8] |= 1 << byte(7-i%8)
+		}
+	}
+	if len(nonZeroBytes) == 0 {
+		return nil
+	}
+	return append(bitsetEncodeBytes(nonZeroBitset), nonZeroBytes...)
+}
+
+// DecompressBytes decompresses data with a known target size. If the input data
+// matches the size of the target, it means no compression was done in the first
+// place.
+func DecompressBytes(data []byte, target int) ([]byte, error) {
+	if len(data) > target {
+		return nil, errExceededTarget
+	}
+	if len(data) == target {
+		cpy := make([]byte, len(data))
+		copy(cpy, data)
+		return cpy, nil
+	}
+	return bitsetDecodeBytes(data, target)
+}
+
+// bitsetDecodeBytes decompresses data with a known target size.
+func bitsetDecodeBytes(data []byte, target int) ([]byte, error) {
+	out, size, err := bitsetDecodePartialBytes(data, target)
+	if err != nil {
+		return nil, err
+	}
+	if size != len(data) {
+		return nil, errUnreferencedData
+	}
+	return out, nil
+}
+
+// bitsetDecodePartialBytes decompresses data with a known target size, but does
+// not enforce consuming all the input bytes. In addition to the decompressed
+// output, the function returns the length of compressed input data corresponding
+// to the output as the input slice may be longer.
+func bitsetDecodePartialBytes(data []byte, target int) ([]byte, int, error) {
+	// Sanity check 0 targets to avoid infinite recursion
+	if target == 0 {
+		return nil, 0, nil
+	}
+	// Handle the zero and single byte corner cases
+	decomp := make([]byte, target)
+	if len(data) == 0 {
+		return decomp, 0, nil
+	}
+	if target == 1 {
+		decomp[0] = data[0] // copy to avoid referencing the input slice
+		if data[0] != 0 {
+			return decomp, 1, nil
+		}
+		return decomp, 0, nil
+	}
+	// Decompress the bitset of set bytes and distribute the non zero bytes
+	nonZeroBitset, ptr, err := bitsetDecodePartialBytes(data, (target+7)/8)
+	if err != nil {
+		return nil, ptr, err
+	}
+	for i := 0; i < 8*len(nonZeroBitset); i++ {
+		if nonZeroBitset[i/8]&(1<<byte(7-i%8)) != 0 {
+			// Make sure we have enough data to push into the correct slot
+			if ptr >= len(data) {
+				return nil, 0, errMissingData
+			}
+			if i >= len(decomp) {
+				return nil, 0, errExceededTarget
+			}
+			// Make sure the data is valid and push into the slot
+			if data[ptr] == 0 {
+				return nil, 0, errZeroContent
+			}
+			decomp[i] = data[ptr]
+			ptr++
+		}
+	}
+	return decomp, ptr, nil
+}

+ 181 - 0
common/bitutil/compress_test.go

@@ -0,0 +1,181 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package bitutil
+
+import (
+	"bytes"
+	"math/rand"
+	"testing"
+
+	"github.com/ethereum/go-ethereum/common/hexutil"
+)
+
+// Tests that data bitset encoding and decoding works and is bijective.
+func TestEncodingCycle(t *testing.T) {
+	tests := []string{
+		// Tests generated by go-fuzz to maximize code coverage
+		"0x000000000000000000",
+		"0xef0400",
+		"0xdf7070533534333636313639343638373532313536346c1bc33339343837313070706336343035336336346c65fefb3930393233383838ac2f65fefb",
+		"0x7b64000000",
+		"0x000034000000000000",
+		"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0000000000000000000",
+		"0x4912385c0e7b64000000",
+		"0x000034000000000000000000000000000000",
+		"0x00",
+		"0x000003e834ff7f0000",
+		"0x0000",
+		"0x0000000000000000000000000000000000000000000000000000000000ff00",
+		"0x895f0c6a020f850c6a020f85f88df88d",
+		"0xdf7070533534333636313639343638373432313536346c1bc3315aac2f65fefb",
+		"0x0000000000",
+		"0xdf70706336346c65fefb",
+		"0x00006d643634000000",
+		"0xdf7070533534333636313639343638373532313536346c1bc333393438373130707063363430353639343638373532313536346c1bc333393438336336346c65fe",
+	}
+	for i, tt := range tests {
+		data := hexutil.MustDecode(tt)
+
+		proc, err := bitsetDecodeBytes(bitsetEncodeBytes(data), len(data))
+		if err != nil {
+			t.Errorf("test %d: failed to decompress compressed data: %v", i, err)
+			continue
+		}
+		if !bytes.Equal(data, proc) {
+			t.Errorf("test %d: compress/decompress mismatch: have %x, want %x", i, proc, data)
+		}
+	}
+}
+
+// Tests that data bitset decoding and rencoding works and is bijective.
+func TestDecodingCycle(t *testing.T) {
+	tests := []struct {
+		size  int
+		input string
+		fail  error
+	}{
+		{size: 0, input: "0x"},
+
+		// Crashers generated by go-fuzz
+		{size: 0, input: "0x0020", fail: errUnreferencedData},
+		{size: 0, input: "0x30", fail: errUnreferencedData},
+		{size: 1, input: "0x00", fail: errUnreferencedData},
+		{size: 2, input: "0x07", fail: errMissingData},
+		{size: 1024, input: "0x8000", fail: errZeroContent},
+
+		// Tests generated by go-fuzz to maximize code coverage
+		{size: 29490, input: "0x343137343733323134333839373334323073333930783e3078333930783e70706336346c65303e", fail: errMissingData},
+		{size: 59395, input: "0x00", fail: errUnreferencedData},
+		{size: 52574, input: "0x70706336346c65c0de", fail: errExceededTarget},
+		{size: 42264, input: "0x07", fail: errMissingData},
+		{size: 52, input: "0xa5045bad48f4", fail: errExceededTarget},
+		{size: 52574, input: "0xc0de", fail: errMissingData},
+		{size: 52574, input: "0x"},
+		{size: 29490, input: "0x34313734373332313433383937333432307333393078073034333839373334323073333930783e3078333937333432307333393078073061333930783e70706336346c65303e", fail: errMissingData},
+		{size: 29491, input: "0x3973333930783e30783e", fail: errMissingData},
+
+		{size: 1024, input: "0x808080608080"},
+		{size: 1024, input: "0x808470705e3632383337363033313434303137393130306c6580ef46806380635a80"},
+		{size: 1024, input: "0x8080808070"},
+		{size: 1024, input: "0x808070705e36346c6580ef46806380635a80"},
+		{size: 1024, input: "0x80808046802680"},
+		{size: 1024, input: "0x4040404035"},
+		{size: 1024, input: "0x4040bf3ba2b3f684402d353234373438373934409fe5b1e7ada94ebfd7d0505e27be4035"},
+		{size: 1024, input: "0x404040bf3ba2b3f6844035"},
+		{size: 1024, input: "0x40402d35323437343837393440bfd7d0505e27be4035"},
+	}
+	for i, tt := range tests {
+		data := hexutil.MustDecode(tt.input)
+
+		orig, err := bitsetDecodeBytes(data, tt.size)
+		if err != tt.fail {
+			t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.fail)
+		}
+		if err != nil {
+			continue
+		}
+		if comp := bitsetEncodeBytes(orig); !bytes.Equal(comp, data) {
+			t.Errorf("test %d: decompress/compress mismatch: have %x, want %x", i, comp, data)
+		}
+	}
+}
+
+// TestCompression tests that compression works by returning either the bitset
+// encoded input, or the actual input if the bitset version is longer.
+func TestCompression(t *testing.T) {
+	// Check the compression returns the bitset encoding is shorter
+	in := hexutil.MustDecode("0x4912385c0e7b64000000")
+	out := hexutil.MustDecode("0x80fe4912385c0e7b64")
+
+	if data := CompressBytes(in); !bytes.Equal(data, out) {
+		t.Errorf("encoding mismatch for sparse data: have %x, want %x", data, out)
+	}
+	if data, err := DecompressBytes(out, len(in)); err != nil || !bytes.Equal(data, in) {
+		t.Errorf("decoding mismatch for sparse data: have %x, want %x, error %v", data, in, err)
+	}
+	// Check the compression returns the input if the bitset encoding is longer
+	in = hexutil.MustDecode("0xdf7070533534333636313639343638373532313536346c1bc33339343837313070706336343035336336346c65fefb3930393233383838ac2f65fefb")
+	out = hexutil.MustDecode("0xdf7070533534333636313639343638373532313536346c1bc33339343837313070706336343035336336346c65fefb3930393233383838ac2f65fefb")
+
+	if data := CompressBytes(in); !bytes.Equal(data, out) {
+		t.Errorf("encoding mismatch for dense data: have %x, want %x", data, out)
+	}
+	if data, err := DecompressBytes(out, len(in)); err != nil || !bytes.Equal(data, in) {
+		t.Errorf("decoding mismatch for dense data: have %x, want %x, error %v", data, in, err)
+	}
+	// Check that decompressing a longer input than the target fails
+	if _, err := DecompressBytes([]byte{0xc0, 0x01, 0x01}, 2); err != errExceededTarget {
+		t.Errorf("decoding error mismatch for long data: have %v, want %v", err, errExceededTarget)
+	}
+}
+
+// Crude benchmark for compressing random slices of bytes.
+func BenchmarkEncoding1KBVerySparse(b *testing.B) { benchmarkEncoding(b, 1024, 0.0001) }
+func BenchmarkEncoding2KBVerySparse(b *testing.B) { benchmarkEncoding(b, 2048, 0.0001) }
+func BenchmarkEncoding4KBVerySparse(b *testing.B) { benchmarkEncoding(b, 4096, 0.0001) }
+
+func BenchmarkEncoding1KBSparse(b *testing.B) { benchmarkEncoding(b, 1024, 0.001) }
+func BenchmarkEncoding2KBSparse(b *testing.B) { benchmarkEncoding(b, 2048, 0.001) }
+func BenchmarkEncoding4KBSparse(b *testing.B) { benchmarkEncoding(b, 4096, 0.001) }
+
+func BenchmarkEncoding1KBDense(b *testing.B) { benchmarkEncoding(b, 1024, 0.1) }
+func BenchmarkEncoding2KBDense(b *testing.B) { benchmarkEncoding(b, 2048, 0.1) }
+func BenchmarkEncoding4KBDense(b *testing.B) { benchmarkEncoding(b, 4096, 0.1) }
+
+func BenchmarkEncoding1KBSaturated(b *testing.B) { benchmarkEncoding(b, 1024, 0.5) }
+func BenchmarkEncoding2KBSaturated(b *testing.B) { benchmarkEncoding(b, 2048, 0.5) }
+func BenchmarkEncoding4KBSaturated(b *testing.B) { benchmarkEncoding(b, 4096, 0.5) }
+
+func benchmarkEncoding(b *testing.B, bytes int, fill float64) {
+	// Generate a random slice of bytes to compress
+	random := rand.NewSource(0) // reproducible and comparable
+
+	data := make([]byte, bytes)
+	bits := int(float64(bytes) * 8 * fill)
+
+	for i := 0; i < bits; i++ {
+		idx := random.Int63() % int64(len(data))
+		bit := uint(random.Int63() % 8)
+		data[idx] |= 1 << bit
+	}
+	// Reset the benchmark and measure encoding/decoding
+	b.ResetTimer()
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		bitsetDecodeBytes(bitsetEncodeBytes(data), len(data))
+	}
+}

+ 139 - 0
common/bytes.go

@@ -0,0 +1,139 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// Package common contains various helper functions.
+package common
+
+import (
+	"encoding/hex"
+)
+
+// FromHex returns the bytes represented by the hexadecimal string s.
+// s may be prefixed with "0x".
+func FromHex(s string) []byte {
+	if has0xPrefix(s) {
+		s = s[2:]
+	}
+	if len(s)%2 == 1 {
+		s = "0" + s
+	}
+	return Hex2Bytes(s)
+}
+
+// CopyBytes returns an exact copy of the provided bytes.
+func CopyBytes(b []byte) (copiedBytes []byte) {
+	if b == nil {
+		return nil
+	}
+	copiedBytes = make([]byte, len(b))
+	copy(copiedBytes, b)
+
+	return
+}
+
+// has0xPrefix validates str begins with '0x' or '0X'.
+func has0xPrefix(str string) bool {
+	return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')
+}
+
+// isHexCharacter returns bool of c being a valid hexadecimal.
+func isHexCharacter(c byte) bool {
+	return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')
+}
+
+// isHex validates whether each byte is valid hexadecimal string.
+func isHex(str string) bool {
+	if len(str)%2 != 0 {
+		return false
+	}
+	for _, c := range []byte(str) {
+		if !isHexCharacter(c) {
+			return false
+		}
+	}
+	return true
+}
+
+// Bytes2Hex returns the hexadecimal encoding of d.
+func Bytes2Hex(d []byte) string {
+	return hex.EncodeToString(d)
+}
+
+// Hex2Bytes returns the bytes represented by the hexadecimal string str.
+func Hex2Bytes(str string) []byte {
+	h, _ := hex.DecodeString(str)
+	return h
+}
+
+// Hex2BytesFixed returns bytes of a specified fixed length flen.
+func Hex2BytesFixed(str string, flen int) []byte {
+	h, _ := hex.DecodeString(str)
+	if len(h) == flen {
+		return h
+	}
+	if len(h) > flen {
+		return h[len(h)-flen:]
+	}
+	hh := make([]byte, flen)
+	copy(hh[flen-len(h):flen], h)
+	return hh
+}
+
+// RightPadBytes zero-pads slice to the right up to length l.
+func RightPadBytes(slice []byte, l int) []byte {
+	if l <= len(slice) {
+		return slice
+	}
+
+	padded := make([]byte, l)
+	copy(padded, slice)
+
+	return padded
+}
+
+// LeftPadBytes zero-pads slice to the left up to length l.
+func LeftPadBytes(slice []byte, l int) []byte {
+	if l <= len(slice) {
+		return slice
+	}
+
+	padded := make([]byte, l)
+	copy(padded[l-len(slice):], slice)
+
+	return padded
+}
+
+// TrimLeftZeroes returns a subslice of s without leading zeroes
+func TrimLeftZeroes(s []byte) []byte {
+	idx := 0
+	for ; idx < len(s); idx++ {
+		if s[idx] != 0 {
+			break
+		}
+	}
+	return s[idx:]
+}
+
+// TrimRightZeroes returns a subslice of s without trailing zeroes
+func TrimRightZeroes(s []byte) []byte {
+	idx := len(s)
+	for ; idx > 0; idx-- {
+		if s[idx-1] != 0 {
+			break
+		}
+	}
+	return s[:idx]
+}

+ 126 - 0
common/bytes_test.go

@@ -0,0 +1,126 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package common
+
+import (
+	"bytes"
+	"testing"
+)
+
+func TestCopyBytes(t *testing.T) {
+	input := []byte{1, 2, 3, 4}
+
+	v := CopyBytes(input)
+	if !bytes.Equal(v, []byte{1, 2, 3, 4}) {
+		t.Fatal("not equal after copy")
+	}
+	v[0] = 99
+	if bytes.Equal(v, input) {
+		t.Fatal("result is not a copy")
+	}
+}
+
+func TestLeftPadBytes(t *testing.T) {
+	val := []byte{1, 2, 3, 4}
+	padded := []byte{0, 0, 0, 0, 1, 2, 3, 4}
+
+	if r := LeftPadBytes(val, 8); !bytes.Equal(r, padded) {
+		t.Fatalf("LeftPadBytes(%v, 8) == %v", val, r)
+	}
+	if r := LeftPadBytes(val, 2); !bytes.Equal(r, val) {
+		t.Fatalf("LeftPadBytes(%v, 2) == %v", val, r)
+	}
+}
+
+func TestRightPadBytes(t *testing.T) {
+	val := []byte{1, 2, 3, 4}
+	padded := []byte{1, 2, 3, 4, 0, 0, 0, 0}
+
+	if r := RightPadBytes(val, 8); !bytes.Equal(r, padded) {
+		t.Fatalf("RightPadBytes(%v, 8) == %v", val, r)
+	}
+	if r := RightPadBytes(val, 2); !bytes.Equal(r, val) {
+		t.Fatalf("RightPadBytes(%v, 2) == %v", val, r)
+	}
+}
+
+func TestFromHex(t *testing.T) {
+	input := "0x01"
+	expected := []byte{1}
+	result := FromHex(input)
+	if !bytes.Equal(expected, result) {
+		t.Errorf("Expected %x got %x", expected, result)
+	}
+}
+
+func TestIsHex(t *testing.T) {
+	tests := []struct {
+		input string
+		ok    bool
+	}{
+		{"", true},
+		{"0", false},
+		{"00", true},
+		{"a9e67e", true},
+		{"A9E67E", true},
+		{"0xa9e67e", false},
+		{"a9e67e001", false},
+		{"0xHELLO_MY_NAME_IS_STEVEN_@#$^&*", false},
+	}
+	for _, test := range tests {
+		if ok := isHex(test.input); ok != test.ok {
+			t.Errorf("isHex(%q) = %v, want %v", test.input, ok, test.ok)
+		}
+	}
+}
+
+func TestFromHexOddLength(t *testing.T) {
+	input := "0x1"
+	expected := []byte{1}
+	result := FromHex(input)
+	if !bytes.Equal(expected, result) {
+		t.Errorf("Expected %x got %x", expected, result)
+	}
+}
+
+func TestNoPrefixShortHexOddLength(t *testing.T) {
+	input := "1"
+	expected := []byte{1}
+	result := FromHex(input)
+	if !bytes.Equal(expected, result) {
+		t.Errorf("Expected %x got %x", expected, result)
+	}
+}
+
+func TestTrimRightZeroes(t *testing.T) {
+	tests := []struct {
+		arr []byte
+		exp []byte
+	}{
+		{FromHex("0x00ffff00ff0000"), FromHex("0x00ffff00ff")},
+		{FromHex("0x00000000000000"), []byte{}},
+		{FromHex("0xff"), FromHex("0xff")},
+		{[]byte{}, []byte{}},
+		{FromHex("0x00ffffffffffff"), FromHex("0x00ffffffffffff")},
+	}
+	for i, test := range tests {
+		got := TrimRightZeroes(test.arr)
+		if !bytes.Equal(got, test.exp) {
+			t.Errorf("test %d, got %x exp %x", i, got, test.exp)
+		}
+	}
+}

+ 65 - 0
common/compiler/helpers.go

@@ -0,0 +1,65 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// Package compiler wraps the Solidity and Vyper compiler executables (solc; vyper).
+package compiler
+
+import (
+	"bytes"
+	"io/ioutil"
+	"regexp"
+)
+
+var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`)
+
+// Contract contains information about a compiled contract, alongside its code and runtime code.
+type Contract struct {
+	Code        string            `json:"code"`
+	RuntimeCode string            `json:"runtime-code"`
+	Info        ContractInfo      `json:"info"`
+	Hashes      map[string]string `json:"hashes"`
+}
+
+// ContractInfo contains information about a compiled contract, including access
+// to the ABI definition, source mapping, user and developer docs, and metadata.
+//
+// Depending on the source, language version, compiler version, and compiler
+// options will provide information about how the contract was compiled.
+type ContractInfo struct {
+	Source          string      `json:"source"`
+	Language        string      `json:"language"`
+	LanguageVersion string      `json:"languageVersion"`
+	CompilerVersion string      `json:"compilerVersion"`
+	CompilerOptions string      `json:"compilerOptions"`
+	SrcMap          interface{} `json:"srcMap"`
+	SrcMapRuntime   string      `json:"srcMapRuntime"`
+	AbiDefinition   interface{} `json:"abiDefinition"`
+	UserDoc         interface{} `json:"userDoc"`
+	DeveloperDoc    interface{} `json:"developerDoc"`
+	Metadata        string      `json:"metadata"`
+}
+
+func slurpFiles(files []string) (string, error) {
+	var concat bytes.Buffer
+	for _, file := range files {
+		content, err := ioutil.ReadFile(file)
+		if err != nil {
+			return "", err
+		}
+		concat.Write(content)
+	}
+	return concat.String(), nil
+}

+ 224 - 0
common/compiler/solidity.go

@@ -0,0 +1,224 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// Package compiler wraps the Solidity and Vyper compiler executables (solc; vyper).
+package compiler
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"os/exec"
+	"strconv"
+	"strings"
+)
+
+// Solidity contains information about the solidity compiler.
+type Solidity struct {
+	Path, Version, FullVersion string
+	Major, Minor, Patch        int
+}
+
+// --combined-output format
+type solcOutput struct {
+	Contracts map[string]struct {
+		BinRuntime                                  string `json:"bin-runtime"`
+		SrcMapRuntime                               string `json:"srcmap-runtime"`
+		Bin, SrcMap, Abi, Devdoc, Userdoc, Metadata string
+		Hashes                                      map[string]string
+	}
+	Version string
+}
+
+// solidity v.0.8 changes the way ABI, Devdoc and Userdoc are serialized
+type solcOutputV8 struct {
+	Contracts map[string]struct {
+		BinRuntime            string `json:"bin-runtime"`
+		SrcMapRuntime         string `json:"srcmap-runtime"`
+		Bin, SrcMap, Metadata string
+		Abi                   interface{}
+		Devdoc                interface{}
+		Userdoc               interface{}
+		Hashes                map[string]string
+	}
+	Version string
+}
+
+func (s *Solidity) makeArgs() []string {
+	p := []string{
+		"--combined-json", "bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc",
+		"--optimize",                  // code optimizer switched on
+		"--allow-paths", "., ./, ../", // default to support relative paths
+	}
+	if s.Major > 0 || s.Minor > 4 || s.Patch > 6 {
+		p[1] += ",metadata,hashes"
+	}
+	return p
+}
+
+// SolidityVersion runs solc and parses its version output.
+func SolidityVersion(solc string) (*Solidity, error) {
+	if solc == "" {
+		solc = "solc"
+	}
+	var out bytes.Buffer
+	cmd := exec.Command(solc, "--version")
+	cmd.Stdout = &out
+	err := cmd.Run()
+	if err != nil {
+		return nil, err
+	}
+	matches := versionRegexp.FindStringSubmatch(out.String())
+	if len(matches) != 4 {
+		return nil, fmt.Errorf("can't parse solc version %q", out.String())
+	}
+	s := &Solidity{Path: cmd.Path, FullVersion: out.String(), Version: matches[0]}
+	if s.Major, err = strconv.Atoi(matches[1]); err != nil {
+		return nil, err
+	}
+	if s.Minor, err = strconv.Atoi(matches[2]); err != nil {
+		return nil, err
+	}
+	if s.Patch, err = strconv.Atoi(matches[3]); err != nil {
+		return nil, err
+	}
+	return s, nil
+}
+
+// CompileSolidityString builds and returns all the contracts contained within a source string.
+func CompileSolidityString(solc, source string) (map[string]*Contract, error) {
+	if len(source) == 0 {
+		return nil, errors.New("solc: empty source string")
+	}
+	s, err := SolidityVersion(solc)
+	if err != nil {
+		return nil, err
+	}
+	args := append(s.makeArgs(), "--")
+	cmd := exec.Command(s.Path, append(args, "-")...)
+	cmd.Stdin = strings.NewReader(source)
+	return s.run(cmd, source)
+}
+
+// CompileSolidity compiles all given Solidity source files.
+func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, error) {
+	if len(sourcefiles) == 0 {
+		return nil, errors.New("solc: no source files")
+	}
+	source, err := slurpFiles(sourcefiles)
+	if err != nil {
+		return nil, err
+	}
+	s, err := SolidityVersion(solc)
+	if err != nil {
+		return nil, err
+	}
+	args := append(s.makeArgs(), "--")
+	cmd := exec.Command(s.Path, append(args, sourcefiles...)...)
+	return s.run(cmd, source)
+}
+
+func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, error) {
+	var stderr, stdout bytes.Buffer
+	cmd.Stderr = &stderr
+	cmd.Stdout = &stdout
+	if err := cmd.Run(); err != nil {
+		return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes())
+	}
+	return ParseCombinedJSON(stdout.Bytes(), source, s.Version, s.Version, strings.Join(s.makeArgs(), " "))
+}
+
+// ParseCombinedJSON takes the direct output of a solc --combined-output run and
+// parses it into a map of string contract name to Contract structs. The
+// provided source, language and compiler version, and compiler options are all
+// passed through into the Contract structs.
+//
+// The solc output is expected to contain ABI, source mapping, user docs, and dev docs.
+//
+// Returns an error if the JSON is malformed or missing data, or if the JSON
+// embedded within the JSON is malformed.
+func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) {
+	var output solcOutput
+	if err := json.Unmarshal(combinedJSON, &output); err != nil {
+		// Try to parse the output with the new solidity v.0.8.0 rules
+		return parseCombinedJSONV8(combinedJSON, source, languageVersion, compilerVersion, compilerOptions)
+	}
+	// Compilation succeeded, assemble and return the contracts.
+	contracts := make(map[string]*Contract)
+	for name, info := range output.Contracts {
+		// Parse the individual compilation results.
+		var abi interface{}
+		if err := json.Unmarshal([]byte(info.Abi), &abi); err != nil {
+			return nil, fmt.Errorf("solc: error reading abi definition (%v)", err)
+		}
+		var userdoc, devdoc interface{}
+		json.Unmarshal([]byte(info.Userdoc), &userdoc)
+		json.Unmarshal([]byte(info.Devdoc), &devdoc)
+
+		contracts[name] = &Contract{
+			Code:        "0x" + info.Bin,
+			RuntimeCode: "0x" + info.BinRuntime,
+			Hashes:      info.Hashes,
+			Info: ContractInfo{
+				Source:          source,
+				Language:        "Solidity",
+				LanguageVersion: languageVersion,
+				CompilerVersion: compilerVersion,
+				CompilerOptions: compilerOptions,
+				SrcMap:          info.SrcMap,
+				SrcMapRuntime:   info.SrcMapRuntime,
+				AbiDefinition:   abi,
+				UserDoc:         userdoc,
+				DeveloperDoc:    devdoc,
+				Metadata:        info.Metadata,
+			},
+		}
+	}
+	return contracts, nil
+}
+
+// parseCombinedJSONV8 parses the direct output of solc --combined-output
+// and parses it using the rules from solidity v.0.8.0 and later.
+func parseCombinedJSONV8(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) {
+	var output solcOutputV8
+	if err := json.Unmarshal(combinedJSON, &output); err != nil {
+		return nil, err
+	}
+	// Compilation succeeded, assemble and return the contracts.
+	contracts := make(map[string]*Contract)
+	for name, info := range output.Contracts {
+		contracts[name] = &Contract{
+			Code:        "0x" + info.Bin,
+			RuntimeCode: "0x" + info.BinRuntime,
+			Hashes:      info.Hashes,
+			Info: ContractInfo{
+				Source:          source,
+				Language:        "Solidity",
+				LanguageVersion: languageVersion,
+				CompilerVersion: compilerVersion,
+				CompilerOptions: compilerOptions,
+				SrcMap:          info.SrcMap,
+				SrcMapRuntime:   info.SrcMapRuntime,
+				AbiDefinition:   info.Abi,
+				UserDoc:         info.Userdoc,
+				DeveloperDoc:    info.Devdoc,
+				Metadata:        info.Metadata,
+			},
+		}
+	}
+	return contracts, nil
+}

+ 78 - 0
common/compiler/solidity_test.go

@@ -0,0 +1,78 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package compiler
+
+import (
+	"os/exec"
+	"testing"
+)
+
+const (
+	testSource = `
+pragma solidity >0.0.0;
+contract test {
+   /// @notice Will multiply ` + "`a`" + ` by 7.
+   function multiply(uint a) public returns(uint d) {
+       return a * 7;
+   }
+}
+`
+)
+
+func skipWithoutSolc(t *testing.T) {
+	if _, err := exec.LookPath("solc"); err != nil {
+		t.Skip(err)
+	}
+}
+
+func TestSolidityCompiler(t *testing.T) {
+	skipWithoutSolc(t)
+
+	contracts, err := CompileSolidityString("", testSource)
+	if err != nil {
+		t.Fatalf("error compiling source. result %v: %v", contracts, err)
+	}
+	if len(contracts) != 1 {
+		t.Errorf("one contract expected, got %d", len(contracts))
+	}
+	c, ok := contracts["test"]
+	if !ok {
+		c, ok = contracts["<stdin>:test"]
+		if !ok {
+			t.Fatal("info for contract 'test' not present in result")
+		}
+	}
+	if c.Code == "" {
+		t.Error("empty code")
+	}
+	if c.Info.Source != testSource {
+		t.Error("wrong source")
+	}
+	if c.Info.CompilerVersion == "" {
+		t.Error("empty version")
+	}
+}
+
+func TestSolidityCompileError(t *testing.T) {
+	skipWithoutSolc(t)
+
+	contracts, err := CompileSolidityString("", testSource[4:])
+	if err == nil {
+		t.Errorf("error expected compiling source. got none. result %v", contracts)
+	}
+	t.Logf("error: %v", err)
+}

+ 3 - 0
common/compiler/test.v.py

@@ -0,0 +1,3 @@
+@public
+def test():
+    hello: int128

+ 3 - 0
common/compiler/test_bad.v.py

@@ -0,0 +1,3 @@
+lic
+def test():
+    hello: int128

+ 144 - 0
common/compiler/vyper.go

@@ -0,0 +1,144 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// Package compiler wraps the Solidity and Vyper compiler executables (solc; vyper).
+package compiler
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"os/exec"
+	"strconv"
+	"strings"
+)
+
+// Vyper contains information about the vyper compiler.
+type Vyper struct {
+	Path, Version, FullVersion string
+	Major, Minor, Patch        int
+}
+
+func (s *Vyper) makeArgs() []string {
+	p := []string{
+		"-f", "combined_json",
+	}
+	return p
+}
+
+// VyperVersion runs vyper and parses its version output.
+func VyperVersion(vyper string) (*Vyper, error) {
+	if vyper == "" {
+		vyper = "vyper"
+	}
+	var out bytes.Buffer
+	cmd := exec.Command(vyper, "--version")
+	cmd.Stdout = &out
+	err := cmd.Run()
+	if err != nil {
+		return nil, err
+	}
+	matches := versionRegexp.FindStringSubmatch(out.String())
+	if len(matches) != 4 {
+		return nil, fmt.Errorf("can't parse vyper version %q", out.String())
+	}
+	s := &Vyper{Path: cmd.Path, FullVersion: out.String(), Version: matches[0]}
+	if s.Major, err = strconv.Atoi(matches[1]); err != nil {
+		return nil, err
+	}
+	if s.Minor, err = strconv.Atoi(matches[2]); err != nil {
+		return nil, err
+	}
+	if s.Patch, err = strconv.Atoi(matches[3]); err != nil {
+		return nil, err
+	}
+	return s, nil
+}
+
+// CompileVyper compiles all given Vyper source files.
+func CompileVyper(vyper string, sourcefiles ...string) (map[string]*Contract, error) {
+	if len(sourcefiles) == 0 {
+		return nil, errors.New("vyper: no source files")
+	}
+	source, err := slurpFiles(sourcefiles)
+	if err != nil {
+		return nil, err
+	}
+	s, err := VyperVersion(vyper)
+	if err != nil {
+		return nil, err
+	}
+	args := s.makeArgs()
+	cmd := exec.Command(s.Path, append(args, sourcefiles...)...)
+	return s.run(cmd, source)
+}
+
+func (s *Vyper) run(cmd *exec.Cmd, source string) (map[string]*Contract, error) {
+	var stderr, stdout bytes.Buffer
+	cmd.Stderr = &stderr
+	cmd.Stdout = &stdout
+	if err := cmd.Run(); err != nil {
+		return nil, fmt.Errorf("vyper: %v\n%s", err, stderr.Bytes())
+	}
+
+	return ParseVyperJSON(stdout.Bytes(), source, s.Version, s.Version, strings.Join(s.makeArgs(), " "))
+}
+
+// ParseVyperJSON takes the direct output of a vyper --f combined_json run and
+// parses it into a map of string contract name to Contract structs. The
+// provided source, language and compiler version, and compiler options are all
+// passed through into the Contract structs.
+//
+// The vyper output is expected to contain ABI and source mapping.
+//
+// Returns an error if the JSON is malformed or missing data, or if the JSON
+// embedded within the JSON is malformed.
+func ParseVyperJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) {
+	var output map[string]interface{}
+	if err := json.Unmarshal(combinedJSON, &output); err != nil {
+		return nil, err
+	}
+
+	// Compilation succeeded, assemble and return the contracts.
+	contracts := make(map[string]*Contract)
+	for name, info := range output {
+		// Parse the individual compilation results.
+		if name == "version" {
+			continue
+		}
+		c := info.(map[string]interface{})
+
+		contracts[name] = &Contract{
+			Code:        c["bytecode"].(string),
+			RuntimeCode: c["bytecode_runtime"].(string),
+			Info: ContractInfo{
+				Source:          source,
+				Language:        "Vyper",
+				LanguageVersion: languageVersion,
+				CompilerVersion: compilerVersion,
+				CompilerOptions: compilerOptions,
+				SrcMap:          c["source_map"],
+				SrcMapRuntime:   "",
+				AbiDefinition:   c["abi"],
+				UserDoc:         "",
+				DeveloperDoc:    "",
+				Metadata:        "",
+			},
+		}
+	}
+	return contracts, nil
+}

+ 71 - 0
common/compiler/vyper_test.go

@@ -0,0 +1,71 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package compiler
+
+import (
+	"os/exec"
+	"testing"
+)
+
+func skipWithoutVyper(t *testing.T) {
+	if _, err := exec.LookPath("vyper"); err != nil {
+		t.Skip(err)
+	}
+}
+
+func TestVyperCompiler(t *testing.T) {
+	skipWithoutVyper(t)
+
+	testSource := []string{"test.v.py"}
+	source, err := slurpFiles(testSource)
+	if err != nil {
+		t.Error("couldn't read test files")
+	}
+	contracts, err := CompileVyper("", testSource...)
+	if err != nil {
+		t.Fatalf("error compiling test.v.py. result %v: %v", contracts, err)
+	}
+	if len(contracts) != 1 {
+		t.Errorf("one contract expected, got %d", len(contracts))
+	}
+	c, ok := contracts["test.v.py"]
+	if !ok {
+		c, ok = contracts["<stdin>:test"]
+		if !ok {
+			t.Fatal("info for contract 'test.v.py' not present in result")
+		}
+	}
+	if c.Code == "" {
+		t.Error("empty code")
+	}
+	if c.Info.Source != source {
+		t.Error("wrong source")
+	}
+	if c.Info.CompilerVersion == "" {
+		t.Error("empty version")
+	}
+}
+
+func TestVyperCompileError(t *testing.T) {
+	skipWithoutVyper(t)
+
+	contracts, err := CompileVyper("", "test_bad.v.py")
+	if err == nil {
+		t.Errorf("error expected compiling test_bad.v.py. got none. result %v", contracts)
+	}
+	t.Logf("error: %v", err)
+}

+ 52 - 0
common/debug.go

@@ -0,0 +1,52 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package common
+
+import (
+	"fmt"
+	"os"
+	"runtime"
+	"runtime/debug"
+	"strings"
+)
+
+// Report gives off a warning requesting the user to submit an issue to the github tracker.
+func Report(extra ...interface{}) {
+	fmt.Fprintln(os.Stderr, "You've encountered a sought after, hard to reproduce bug. Please report this to the developers <3 https://github.com/ethereum/go-ethereum/issues")
+	fmt.Fprintln(os.Stderr, extra...)
+
+	_, file, line, _ := runtime.Caller(1)
+	fmt.Fprintf(os.Stderr, "%v:%v\n", file, line)
+
+	debug.PrintStack()
+
+	fmt.Fprintln(os.Stderr, "#### BUG! PLEASE REPORT ####")
+}
+
+// PrintDepricationWarning prinst the given string in a box using fmt.Println.
+func PrintDepricationWarning(str string) {
+	line := strings.Repeat("#", len(str)+4)
+	emptyLine := strings.Repeat(" ", len(str))
+	fmt.Printf(`
+%s
+# %s #
+# %s #
+# %s #
+%s
+
+`, line, emptyLine, str, emptyLine, line)
+}

+ 67 - 0
common/fdlimit/fdlimit_bsd.go

@@ -0,0 +1,67 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build freebsd dragonfly
+
+package fdlimit
+
+import "syscall"
+
+// This file is largely identical to fdlimit_unix.go,
+// but Rlimit fields have type int64 on *BSD so it needs
+// an extra conversion.
+
+// Raise tries to maximize the file descriptor allowance of this process
+// to the maximum hard-limit allowed by the OS.
+func Raise(max uint64) (uint64, error) {
+	// Get the current limit
+	var limit syscall.Rlimit
+	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	// Try to update the limit to the max allowance
+	limit.Cur = limit.Max
+	if limit.Cur > int64(max) {
+		limit.Cur = int64(max)
+	}
+	if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	return uint64(limit.Cur), nil
+}
+
+// Current retrieves the number of file descriptors allowed to be opened by this
+// process.
+func Current() (int, error) {
+	var limit syscall.Rlimit
+	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	return int(limit.Cur), nil
+}
+
+// Maximum retrieves the maximum number of file descriptors this process is
+// allowed to request for itself.
+func Maximum() (int, error) {
+	var limit syscall.Rlimit
+	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	return int(limit.Max), nil
+}

+ 71 - 0
common/fdlimit/fdlimit_darwin.go

@@ -0,0 +1,71 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package fdlimit
+
+import "syscall"
+
+// hardlimit is the number of file descriptors allowed at max by the kernel.
+const hardlimit = 10240
+
+// Raise tries to maximize the file descriptor allowance of this process
+// to the maximum hard-limit allowed by the OS.
+// Returns the size it was set to (may differ from the desired 'max')
+func Raise(max uint64) (uint64, error) {
+	// Get the current limit
+	var limit syscall.Rlimit
+	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	// Try to update the limit to the max allowance
+	limit.Cur = limit.Max
+	if limit.Cur > max {
+		limit.Cur = max
+	}
+	if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	// MacOS can silently apply further caps, so retrieve the actually set limit
+	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	return limit.Cur, nil
+}
+
+// Current retrieves the number of file descriptors allowed to be opened by this
+// process.
+func Current() (int, error) {
+	var limit syscall.Rlimit
+	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	return int(limit.Cur), nil
+}
+
+// Maximum retrieves the maximum number of file descriptors this process is
+// allowed to request for itself.
+func Maximum() (int, error) {
+	// Retrieve the maximum allowed by dynamic OS limits
+	var limit syscall.Rlimit
+	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	// Cap it to OPEN_MAX (10240) because macos is a special snowflake
+	if limit.Max > hardlimit {
+		limit.Max = hardlimit
+	}
+	return int(limit.Max), nil
+}

+ 45 - 0
common/fdlimit/fdlimit_test.go

@@ -0,0 +1,45 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package fdlimit
+
+import (
+	"fmt"
+	"testing"
+)
+
+// TestFileDescriptorLimits simply tests whether the file descriptor allowance
+// per this process can be retrieved.
+func TestFileDescriptorLimits(t *testing.T) {
+	target := 4096
+	hardlimit, err := Maximum()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if hardlimit < target {
+		t.Skip(fmt.Sprintf("system limit is less than desired test target: %d < %d", hardlimit, target))
+	}
+
+	if limit, err := Current(); err != nil || limit <= 0 {
+		t.Fatalf("failed to retrieve file descriptor limit (%d): %v", limit, err)
+	}
+	if _, err := Raise(uint64(target)); err != nil {
+		t.Fatalf("failed to raise file allowance")
+	}
+	if limit, err := Current(); err != nil || limit < target {
+		t.Fatalf("failed to retrieve raised descriptor limit (have %v, want %v): %v", limit, target, err)
+	}
+}

+ 65 - 0
common/fdlimit/fdlimit_unix.go

@@ -0,0 +1,65 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build linux netbsd openbsd solaris
+
+package fdlimit
+
+import "syscall"
+
+// Raise tries to maximize the file descriptor allowance of this process
+// to the maximum hard-limit allowed by the OS.
+// Returns the size it was set to (may differ from the desired 'max')
+func Raise(max uint64) (uint64, error) {
+	// Get the current limit
+	var limit syscall.Rlimit
+	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	// Try to update the limit to the max allowance
+	limit.Cur = limit.Max
+	if limit.Cur > max {
+		limit.Cur = max
+	}
+	if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	// MacOS can silently apply further caps, so retrieve the actually set limit
+	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	return limit.Cur, nil
+}
+
+// Current retrieves the number of file descriptors allowed to be opened by this
+// process.
+func Current() (int, error) {
+	var limit syscall.Rlimit
+	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	return int(limit.Cur), nil
+}
+
+// Maximum retrieves the maximum number of file descriptors this process is
+// allowed to request for itself.
+func Maximum() (int, error) {
+	var limit syscall.Rlimit
+	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+		return 0, err
+	}
+	return int(limit.Max), nil
+}

+ 50 - 0
common/fdlimit/fdlimit_windows.go

@@ -0,0 +1,50 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package fdlimit
+
+import "fmt"
+
+// hardlimit is the number of file descriptors allowed at max by the kernel.
+const hardlimit = 16384
+
+// Raise tries to maximize the file descriptor allowance of this process
+// to the maximum hard-limit allowed by the OS.
+func Raise(max uint64) (uint64, error) {
+	// This method is NOP by design:
+	//  * Linux/Darwin counterparts need to manually increase per process limits
+	//  * On Windows Go uses the CreateFile API, which is limited to 16K files, non
+	//    changeable from within a running process
+	// This way we can always "request" raising the limits, which will either have
+	// or not have effect based on the platform we're running on.
+	if max > hardlimit {
+		return hardlimit, fmt.Errorf("file descriptor limit (%d) reached", hardlimit)
+	}
+	return max, nil
+}
+
+// Current retrieves the number of file descriptors allowed to be opened by this
+// process.
+func Current() (int, error) {
+	// Please see Raise for the reason why we use hard coded 16K as the limit
+	return hardlimit, nil
+}
+
+// Maximum retrieves the maximum number of file descriptors this process is
+// allowed to request for itself.
+func Maximum() (int, error) {
+	return Current()
+}

+ 82 - 0
common/format.go

@@ -0,0 +1,82 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package common
+
+import (
+	"fmt"
+	"regexp"
+	"strings"
+	"time"
+)
+
+// PrettyDuration is a pretty printed version of a time.Duration value that cuts
+// the unnecessary precision off from the formatted textual representation.
+type PrettyDuration time.Duration
+
+var prettyDurationRe = regexp.MustCompile(`\.[0-9]+`)
+
+// String implements the Stringer interface, allowing pretty printing of duration
+// values rounded to three decimals.
+func (d PrettyDuration) String() string {
+	label := fmt.Sprintf("%v", time.Duration(d))
+	if match := prettyDurationRe.FindString(label); len(match) > 4 {
+		label = strings.Replace(label, match, match[:4], 1)
+	}
+	return label
+}
+
+// PrettyAge is a pretty printed version of a time.Duration value that rounds
+// the values up to a single most significant unit, days/weeks/years included.
+type PrettyAge time.Time
+
+// ageUnits is a list of units the age pretty printing uses.
+var ageUnits = []struct {
+	Size   time.Duration
+	Symbol string
+}{
+	{12 * 30 * 24 * time.Hour, "y"},
+	{30 * 24 * time.Hour, "mo"},
+	{7 * 24 * time.Hour, "w"},
+	{24 * time.Hour, "d"},
+	{time.Hour, "h"},
+	{time.Minute, "m"},
+	{time.Second, "s"},
+}
+
+// String implements the Stringer interface, allowing pretty printing of duration
+// values rounded to the most significant time unit.
+func (t PrettyAge) String() string {
+	// Calculate the time difference and handle the 0 cornercase
+	diff := time.Since(time.Time(t))
+	if diff < time.Second {
+		return "0"
+	}
+	// Accumulate a precision of 3 components before returning
+	result, prec := "", 0
+
+	for _, unit := range ageUnits {
+		if diff > unit.Size {
+			result = fmt.Sprintf("%s%d%s", result, diff/unit.Size, unit.Symbol)
+			diff %= unit.Size
+
+			if prec += 1; prec >= 3 {
+				break
+			}
+		}
+	}
+	return result
+}

+ 59 - 0
common/gopool/pool.go

@@ -0,0 +1,59 @@
+package gopool
+
+import (
+    "github.com/panjf2000/ants/v2"
+    "runtime"
+    "time"
+)
+
+var (
+    // Init a instance pool when importing ants.
+    defaultPool, _   = ants.NewPool(ants.DefaultAntsPoolSize, ants.WithExpiryDuration(10*time.Second))
+    minNumberPerTask = 5
+)
+
+// Logger is used for logging formatted messages.
+type Logger interface {
+    // Printf must have the same semantics as log.Printf.
+    Printf(format string, args ...interface{})
+}
+
+// Submit submits a task to pool.
+func Submit(task func()) error {
+    return defaultPool.Submit(task)
+}
+
+// Running returns the number of the currently running goroutines.
+func Running() int {
+    return defaultPool.Running()
+}
+
+// Cap returns the capacity of this default pool.
+func Cap() int {
+    return defaultPool.Cap()
+}
+
+// Free returns the available goroutines to work.
+func Free() int {
+    return defaultPool.Free()
+}
+
+// Release Closes the default pool.
+func Release() {
+    defaultPool.Release()
+}
+
+// Reboot reboots the default pool.
+func Reboot() {
+    defaultPool.Reboot()
+}
+
+func Threads(tasks int) int {
+    threads := tasks / minNumberPerTask
+    if threads > runtime.NumCPU() {
+        threads = runtime.NumCPU()
+    } else if threads == 0 {
+        threads = 1
+    }
+    return threads
+}

+ 240 - 0
common/hexutil/hexutil.go

@@ -0,0 +1,240 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+/*
+Package hexutil implements hex encoding with 0x prefix.
+This encoding is used by the Ethereum RPC API to transport binary data in JSON payloads.
+
+Encoding Rules
+
+All hex data must have prefix "0x".
+
+For byte slices, the hex data must be of even length. An empty byte slice
+encodes as "0x".
+
+Integers are encoded using the least amount of digits (no leading zero digits). Their
+encoding may be of uneven length. The number zero encodes as "0x0".
+*/
+package hexutil
+
+import (
+	"encoding/hex"
+	"fmt"
+	"math/big"
+	"strconv"
+)
+
+const uintBits = 32 << (uint64(^uint(0)) >> 63)
+
+// Errors
+var (
+	ErrEmptyString   = &decError{"empty hex string"}
+	ErrSyntax        = &decError{"invalid hex string"}
+	ErrMissingPrefix = &decError{"hex string without 0x prefix"}
+	ErrOddLength     = &decError{"hex string of odd length"}
+	ErrEmptyNumber   = &decError{"hex string \"0x\""}
+	ErrLeadingZero   = &decError{"hex number with leading zero digits"}
+	ErrUint64Range   = &decError{"hex number > 64 bits"}
+	ErrUintRange     = &decError{fmt.Sprintf("hex number > %d bits", uintBits)}
+	ErrBig256Range   = &decError{"hex number > 256 bits"}
+)
+
+type decError struct{ msg string }
+
+func (err decError) Error() string { return err.msg }
+
+// Decode decodes a hex string with 0x prefix.
+func Decode(input string) ([]byte, error) {
+	if len(input) == 0 {
+		return nil, ErrEmptyString
+	}
+	if !has0xPrefix(input) {
+		return nil, ErrMissingPrefix
+	}
+	b, err := hex.DecodeString(input[2:])
+	if err != nil {
+		err = mapError(err)
+	}
+	return b, err
+}
+
+// MustDecode decodes a hex string with 0x prefix. It panics for invalid input.
+func MustDecode(input string) []byte {
+	dec, err := Decode(input)
+	if err != nil {
+		panic(err)
+	}
+	return dec
+}
+
+// Encode encodes b as a hex string with 0x prefix.
+func Encode(b []byte) string {
+	enc := make([]byte, len(b)*2+2)
+	copy(enc, "0x")
+	hex.Encode(enc[2:], b)
+	return string(enc)
+}
+
+// DecodeUint64 decodes a hex string with 0x prefix as a quantity.
+func DecodeUint64(input string) (uint64, error) {
+	raw, err := checkNumber(input)
+	if err != nil {
+		return 0, err
+	}
+	dec, err := strconv.ParseUint(raw, 16, 64)
+	if err != nil {
+		err = mapError(err)
+	}
+	return dec, err
+}
+
+// MustDecodeUint64 decodes a hex string with 0x prefix as a quantity.
+// It panics for invalid input.
+func MustDecodeUint64(input string) uint64 {
+	dec, err := DecodeUint64(input)
+	if err != nil {
+		panic(err)
+	}
+	return dec
+}
+
+// EncodeUint64 encodes i as a hex string with 0x prefix.
+func EncodeUint64(i uint64) string {
+	enc := make([]byte, 2, 10)
+	copy(enc, "0x")
+	return string(strconv.AppendUint(enc, i, 16))
+}
+
+var bigWordNibbles int
+
+func init() {
+	// This is a weird way to compute the number of nibbles required for big.Word.
+	// The usual way would be to use constant arithmetic but go vet can't handle that.
+	b, _ := new(big.Int).SetString("FFFFFFFFFF", 16)
+	switch len(b.Bits()) {
+	case 1:
+		bigWordNibbles = 16
+	case 2:
+		bigWordNibbles = 8
+	default:
+		panic("weird big.Word size")
+	}
+}
+
+// DecodeBig decodes a hex string with 0x prefix as a quantity.
+// Numbers larger than 256 bits are not accepted.
+func DecodeBig(input string) (*big.Int, error) {
+	raw, err := checkNumber(input)
+	if err != nil {
+		return nil, err
+	}
+	if len(raw) > 64 {
+		return nil, ErrBig256Range
+	}
+	words := make([]big.Word, len(raw)/bigWordNibbles+1)
+	end := len(raw)
+	for i := range words {
+		start := end - bigWordNibbles
+		if start < 0 {
+			start = 0
+		}
+		for ri := start; ri < end; ri++ {
+			nib := decodeNibble(raw[ri])
+			if nib == badNibble {
+				return nil, ErrSyntax
+			}
+			words[i] *= 16
+			words[i] += big.Word(nib)
+		}
+		end = start
+	}
+	dec := new(big.Int).SetBits(words)
+	return dec, nil
+}
+
+// MustDecodeBig decodes a hex string with 0x prefix as a quantity.
+// It panics for invalid input.
+func MustDecodeBig(input string) *big.Int {
+	dec, err := DecodeBig(input)
+	if err != nil {
+		panic(err)
+	}
+	return dec
+}
+
+// EncodeBig encodes bigint as a hex string with 0x prefix.
+// The sign of the integer is ignored.
+func EncodeBig(bigint *big.Int) string {
+	nbits := bigint.BitLen()
+	if nbits == 0 {
+		return "0x0"
+	}
+	return fmt.Sprintf("%#x", bigint)
+}
+
+func has0xPrefix(input string) bool {
+	return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
+}
+
+func checkNumber(input string) (raw string, err error) {
+	if len(input) == 0 {
+		return "", ErrEmptyString
+	}
+	if !has0xPrefix(input) {
+		return "", ErrMissingPrefix
+	}
+	input = input[2:]
+	if len(input) == 0 {
+		return "", ErrEmptyNumber
+	}
+	if len(input) > 1 && input[0] == '0' {
+		return "", ErrLeadingZero
+	}
+	return input, nil
+}
+
+const badNibble = ^uint64(0)
+
+func decodeNibble(in byte) uint64 {
+	switch {
+	case in >= '0' && in <= '9':
+		return uint64(in - '0')
+	case in >= 'A' && in <= 'F':
+		return uint64(in - 'A' + 10)
+	case in >= 'a' && in <= 'f':
+		return uint64(in - 'a' + 10)
+	default:
+		return badNibble
+	}
+}
+
+func mapError(err error) error {
+	if err, ok := err.(*strconv.NumError); ok {
+		switch err.Err {
+		case strconv.ErrRange:
+			return ErrUint64Range
+		case strconv.ErrSyntax:
+			return ErrSyntax
+		}
+	}
+	if _, ok := err.(hex.InvalidByteError); ok {
+		return ErrSyntax
+	}
+	if err == hex.ErrLength {
+		return ErrOddLength
+	}
+	return err
+}

+ 203 - 0
common/hexutil/hexutil_test.go

@@ -0,0 +1,203 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package hexutil
+
+import (
+	"bytes"
+	"math/big"
+	"testing"
+)
+
+type marshalTest struct {
+	input interface{}
+	want  string
+}
+
+type unmarshalTest struct {
+	input        string
+	want         interface{}
+	wantErr      error // if set, decoding must fail on any platform
+	wantErr32bit error // if set, decoding must fail on 32bit platforms (used for Uint tests)
+}
+
+var (
+	encodeBytesTests = []marshalTest{
+		{[]byte{}, "0x"},
+		{[]byte{0}, "0x00"},
+		{[]byte{0, 0, 1, 2}, "0x00000102"},
+	}
+
+	encodeBigTests = []marshalTest{
+		{referenceBig("0"), "0x0"},
+		{referenceBig("1"), "0x1"},
+		{referenceBig("ff"), "0xff"},
+		{referenceBig("112233445566778899aabbccddeeff"), "0x112233445566778899aabbccddeeff"},
+		{referenceBig("80a7f2c1bcc396c00"), "0x80a7f2c1bcc396c00"},
+		{referenceBig("-80a7f2c1bcc396c00"), "-0x80a7f2c1bcc396c00"},
+	}
+
+	encodeUint64Tests = []marshalTest{
+		{uint64(0), "0x0"},
+		{uint64(1), "0x1"},
+		{uint64(0xff), "0xff"},
+		{uint64(0x1122334455667788), "0x1122334455667788"},
+	}
+
+	encodeUintTests = []marshalTest{
+		{uint(0), "0x0"},
+		{uint(1), "0x1"},
+		{uint(0xff), "0xff"},
+		{uint(0x11223344), "0x11223344"},
+	}
+
+	decodeBytesTests = []unmarshalTest{
+		// invalid
+		{input: ``, wantErr: ErrEmptyString},
+		{input: `0`, wantErr: ErrMissingPrefix},
+		{input: `0x0`, wantErr: ErrOddLength},
+		{input: `0x023`, wantErr: ErrOddLength},
+		{input: `0xxx`, wantErr: ErrSyntax},
+		{input: `0x01zz01`, wantErr: ErrSyntax},
+		// valid
+		{input: `0x`, want: []byte{}},
+		{input: `0X`, want: []byte{}},
+		{input: `0x02`, want: []byte{0x02}},
+		{input: `0X02`, want: []byte{0x02}},
+		{input: `0xffffffffff`, want: []byte{0xff, 0xff, 0xff, 0xff, 0xff}},
+		{
+			input: `0xffffffffffffffffffffffffffffffffffff`,
+			want:  []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+		},
+	}
+
+	decodeBigTests = []unmarshalTest{
+		// invalid
+		{input: `0`, wantErr: ErrMissingPrefix},
+		{input: `0x`, wantErr: ErrEmptyNumber},
+		{input: `0x01`, wantErr: ErrLeadingZero},
+		{input: `0xx`, wantErr: ErrSyntax},
+		{input: `0x1zz01`, wantErr: ErrSyntax},
+		{
+			input:   `0x10000000000000000000000000000000000000000000000000000000000000000`,
+			wantErr: ErrBig256Range,
+		},
+		// valid
+		{input: `0x0`, want: big.NewInt(0)},
+		{input: `0x2`, want: big.NewInt(0x2)},
+		{input: `0x2F2`, want: big.NewInt(0x2f2)},
+		{input: `0X2F2`, want: big.NewInt(0x2f2)},
+		{input: `0x1122aaff`, want: big.NewInt(0x1122aaff)},
+		{input: `0xbBb`, want: big.NewInt(0xbbb)},
+		{input: `0xfffffffff`, want: big.NewInt(0xfffffffff)},
+		{
+			input: `0x112233445566778899aabbccddeeff`,
+			want:  referenceBig("112233445566778899aabbccddeeff"),
+		},
+		{
+			input: `0xffffffffffffffffffffffffffffffffffff`,
+			want:  referenceBig("ffffffffffffffffffffffffffffffffffff"),
+		},
+		{
+			input: `0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`,
+			want:  referenceBig("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
+		},
+	}
+
+	decodeUint64Tests = []unmarshalTest{
+		// invalid
+		{input: `0`, wantErr: ErrMissingPrefix},
+		{input: `0x`, wantErr: ErrEmptyNumber},
+		{input: `0x01`, wantErr: ErrLeadingZero},
+		{input: `0xfffffffffffffffff`, wantErr: ErrUint64Range},
+		{input: `0xx`, wantErr: ErrSyntax},
+		{input: `0x1zz01`, wantErr: ErrSyntax},
+		// valid
+		{input: `0x0`, want: uint64(0)},
+		{input: `0x2`, want: uint64(0x2)},
+		{input: `0x2F2`, want: uint64(0x2f2)},
+		{input: `0X2F2`, want: uint64(0x2f2)},
+		{input: `0x1122aaff`, want: uint64(0x1122aaff)},
+		{input: `0xbbb`, want: uint64(0xbbb)},
+		{input: `0xffffffffffffffff`, want: uint64(0xffffffffffffffff)},
+	}
+)
+
+func TestEncode(t *testing.T) {
+	for _, test := range encodeBytesTests {
+		enc := Encode(test.input.([]byte))
+		if enc != test.want {
+			t.Errorf("input %x: wrong encoding %s", test.input, enc)
+		}
+	}
+}
+
+func TestDecode(t *testing.T) {
+	for _, test := range decodeBytesTests {
+		dec, err := Decode(test.input)
+		if !checkError(t, test.input, err, test.wantErr) {
+			continue
+		}
+		if !bytes.Equal(test.want.([]byte), dec) {
+			t.Errorf("input %s: value mismatch: got %x, want %x", test.input, dec, test.want)
+			continue
+		}
+	}
+}
+
+func TestEncodeBig(t *testing.T) {
+	for _, test := range encodeBigTests {
+		enc := EncodeBig(test.input.(*big.Int))
+		if enc != test.want {
+			t.Errorf("input %x: wrong encoding %s", test.input, enc)
+		}
+	}
+}
+
+func TestDecodeBig(t *testing.T) {
+	for _, test := range decodeBigTests {
+		dec, err := DecodeBig(test.input)
+		if !checkError(t, test.input, err, test.wantErr) {
+			continue
+		}
+		if dec.Cmp(test.want.(*big.Int)) != 0 {
+			t.Errorf("input %s: value mismatch: got %x, want %x", test.input, dec, test.want)
+			continue
+		}
+	}
+}
+
+func TestEncodeUint64(t *testing.T) {
+	for _, test := range encodeUint64Tests {
+		enc := EncodeUint64(test.input.(uint64))
+		if enc != test.want {
+			t.Errorf("input %x: wrong encoding %s", test.input, enc)
+		}
+	}
+}
+
+func TestDecodeUint64(t *testing.T) {
+	for _, test := range decodeUint64Tests {
+		dec, err := DecodeUint64(test.input)
+		if !checkError(t, test.input, err, test.wantErr) {
+			continue
+		}
+		if dec != test.want.(uint64) {
+			t.Errorf("input %s: value mismatch: got %x, want %x", test.input, dec, test.want)
+			continue
+		}
+	}
+}

+ 376 - 0
common/hexutil/json.go

@@ -0,0 +1,376 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package hexutil
+
+import (
+	"encoding/hex"
+	"encoding/json"
+	"fmt"
+	"math/big"
+	"reflect"
+	"strconv"
+)
+
+var (
+	bytesT  = reflect.TypeOf(Bytes(nil))
+	bigT    = reflect.TypeOf((*Big)(nil))
+	uintT   = reflect.TypeOf(Uint(0))
+	uint64T = reflect.TypeOf(Uint64(0))
+)
+
+// Bytes marshals/unmarshals as a JSON string with 0x prefix.
+// The empty slice marshals as "0x".
+type Bytes []byte
+
+// MarshalText implements encoding.TextMarshaler
+func (b Bytes) MarshalText() ([]byte, error) {
+	result := make([]byte, len(b)*2+2)
+	copy(result, `0x`)
+	hex.Encode(result[2:], b)
+	return result, nil
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (b *Bytes) UnmarshalJSON(input []byte) error {
+	if !isString(input) {
+		return errNonString(bytesT)
+	}
+	return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), bytesT)
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (b *Bytes) UnmarshalText(input []byte) error {
+	raw, err := checkText(input, true)
+	if err != nil {
+		return err
+	}
+	dec := make([]byte, len(raw)/2)
+	if _, err = hex.Decode(dec, raw); err != nil {
+		err = mapError(err)
+	} else {
+		*b = dec
+	}
+	return err
+}
+
+// String returns the hex encoding of b.
+func (b Bytes) String() string {
+	return Encode(b)
+}
+
+// ImplementsGraphQLType returns true if Bytes implements the specified GraphQL type.
+func (b Bytes) ImplementsGraphQLType(name string) bool { return name == "Bytes" }
+
+// UnmarshalGraphQL unmarshals the provided GraphQL query data.
+func (b *Bytes) UnmarshalGraphQL(input interface{}) error {
+	var err error
+	switch input := input.(type) {
+	case string:
+		data, err := Decode(input)
+		if err != nil {
+			return err
+		}
+		*b = data
+	default:
+		err = fmt.Errorf("unexpected type %T for Bytes", input)
+	}
+	return err
+}
+
+// UnmarshalFixedJSON decodes the input as a string with 0x prefix. The length of out
+// determines the required input length. This function is commonly used to implement the
+// UnmarshalJSON method for fixed-size types.
+func UnmarshalFixedJSON(typ reflect.Type, input, out []byte) error {
+	if !isString(input) {
+		return errNonString(typ)
+	}
+	return wrapTypeError(UnmarshalFixedText(typ.String(), input[1:len(input)-1], out), typ)
+}
+
+// UnmarshalFixedText decodes the input as a string with 0x prefix. The length of out
+// determines the required input length. This function is commonly used to implement the
+// UnmarshalText method for fixed-size types.
+func UnmarshalFixedText(typname string, input, out []byte) error {
+	raw, err := checkText(input, true)
+	if err != nil {
+		return err
+	}
+	if len(raw)/2 != len(out) {
+		return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname)
+	}
+	// Pre-verify syntax before modifying out.
+	for _, b := range raw {
+		if decodeNibble(b) == badNibble {
+			return ErrSyntax
+		}
+	}
+	hex.Decode(out, raw)
+	return nil
+}
+
+// UnmarshalFixedUnprefixedText decodes the input as a string with optional 0x prefix. The
+// length of out determines the required input length. This function is commonly used to
+// implement the UnmarshalText method for fixed-size types.
+func UnmarshalFixedUnprefixedText(typname string, input, out []byte) error {
+	raw, err := checkText(input, false)
+	if err != nil {
+		return err
+	}
+	if len(raw)/2 != len(out) {
+		return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname)
+	}
+	// Pre-verify syntax before modifying out.
+	for _, b := range raw {
+		if decodeNibble(b) == badNibble {
+			return ErrSyntax
+		}
+	}
+	hex.Decode(out, raw)
+	return nil
+}
+
+// Big marshals/unmarshals as a JSON string with 0x prefix.
+// The zero value marshals as "0x0".
+//
+// Negative integers are not supported at this time. Attempting to marshal them will
+// return an error. Values larger than 256bits are rejected by Unmarshal but will be
+// marshaled without error.
+type Big big.Int
+
+// MarshalText implements encoding.TextMarshaler
+func (b Big) MarshalText() ([]byte, error) {
+	return []byte(EncodeBig((*big.Int)(&b))), nil
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (b *Big) UnmarshalJSON(input []byte) error {
+	if !isString(input) {
+		return errNonString(bigT)
+	}
+	return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), bigT)
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler
+func (b *Big) UnmarshalText(input []byte) error {
+	raw, err := checkNumberText(input)
+	if err != nil {
+		return err
+	}
+	if len(raw) > 64 {
+		return ErrBig256Range
+	}
+	words := make([]big.Word, len(raw)/bigWordNibbles+1)
+	end := len(raw)
+	for i := range words {
+		start := end - bigWordNibbles
+		if start < 0 {
+			start = 0
+		}
+		for ri := start; ri < end; ri++ {
+			nib := decodeNibble(raw[ri])
+			if nib == badNibble {
+				return ErrSyntax
+			}
+			words[i] *= 16
+			words[i] += big.Word(nib)
+		}
+		end = start
+	}
+	var dec big.Int
+	dec.SetBits(words)
+	*b = (Big)(dec)
+	return nil
+}
+
+// ToInt converts b to a big.Int.
+func (b *Big) ToInt() *big.Int {
+	return (*big.Int)(b)
+}
+
+// String returns the hex encoding of b.
+func (b *Big) String() string {
+	return EncodeBig(b.ToInt())
+}
+
+// ImplementsGraphQLType returns true if Big implements the provided GraphQL type.
+func (b Big) ImplementsGraphQLType(name string) bool { return name == "BigInt" }
+
+// UnmarshalGraphQL unmarshals the provided GraphQL query data.
+func (b *Big) UnmarshalGraphQL(input interface{}) error {
+	var err error
+	switch input := input.(type) {
+	case string:
+		return b.UnmarshalText([]byte(input))
+	case int32:
+		var num big.Int
+		num.SetInt64(int64(input))
+		*b = Big(num)
+	default:
+		err = fmt.Errorf("unexpected type %T for BigInt", input)
+	}
+	return err
+}
+
+// Uint64 marshals/unmarshals as a JSON string with 0x prefix.
+// The zero value marshals as "0x0".
+type Uint64 uint64
+
+// MarshalText implements encoding.TextMarshaler.
+func (b Uint64) MarshalText() ([]byte, error) {
+	buf := make([]byte, 2, 10)
+	copy(buf, `0x`)
+	buf = strconv.AppendUint(buf, uint64(b), 16)
+	return buf, nil
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (b *Uint64) UnmarshalJSON(input []byte) error {
+	if !isString(input) {
+		return errNonString(uint64T)
+	}
+	return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), uint64T)
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler
+func (b *Uint64) UnmarshalText(input []byte) error {
+	raw, err := checkNumberText(input)
+	if err != nil {
+		return err
+	}
+	if len(raw) > 16 {
+		return ErrUint64Range
+	}
+	var dec uint64
+	for _, byte := range raw {
+		nib := decodeNibble(byte)
+		if nib == badNibble {
+			return ErrSyntax
+		}
+		dec *= 16
+		dec += nib
+	}
+	*b = Uint64(dec)
+	return nil
+}
+
+// String returns the hex encoding of b.
+func (b Uint64) String() string {
+	return EncodeUint64(uint64(b))
+}
+
+// ImplementsGraphQLType returns true if Uint64 implements the provided GraphQL type.
+func (b Uint64) ImplementsGraphQLType(name string) bool { return name == "Long" }
+
+// UnmarshalGraphQL unmarshals the provided GraphQL query data.
+func (b *Uint64) UnmarshalGraphQL(input interface{}) error {
+	var err error
+	switch input := input.(type) {
+	case string:
+		return b.UnmarshalText([]byte(input))
+	case int32:
+		*b = Uint64(input)
+	default:
+		err = fmt.Errorf("unexpected type %T for Long", input)
+	}
+	return err
+}
+
+// Uint marshals/unmarshals as a JSON string with 0x prefix.
+// The zero value marshals as "0x0".
+type Uint uint
+
+// MarshalText implements encoding.TextMarshaler.
+func (b Uint) MarshalText() ([]byte, error) {
+	return Uint64(b).MarshalText()
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (b *Uint) UnmarshalJSON(input []byte) error {
+	if !isString(input) {
+		return errNonString(uintT)
+	}
+	return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), uintT)
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (b *Uint) UnmarshalText(input []byte) error {
+	var u64 Uint64
+	err := u64.UnmarshalText(input)
+	if u64 > Uint64(^uint(0)) || err == ErrUint64Range {
+		return ErrUintRange
+	} else if err != nil {
+		return err
+	}
+	*b = Uint(u64)
+	return nil
+}
+
+// String returns the hex encoding of b.
+func (b Uint) String() string {
+	return EncodeUint64(uint64(b))
+}
+
+func isString(input []byte) bool {
+	return len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"'
+}
+
+func bytesHave0xPrefix(input []byte) bool {
+	return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
+}
+
+func checkText(input []byte, wantPrefix bool) ([]byte, error) {
+	if len(input) == 0 {
+		return nil, nil // empty strings are allowed
+	}
+	if bytesHave0xPrefix(input) {
+		input = input[2:]
+	} else if wantPrefix {
+		return nil, ErrMissingPrefix
+	}
+	if len(input)%2 != 0 {
+		return nil, ErrOddLength
+	}
+	return input, nil
+}
+
+func checkNumberText(input []byte) (raw []byte, err error) {
+	if len(input) == 0 {
+		return nil, nil // empty strings are allowed
+	}
+	if !bytesHave0xPrefix(input) {
+		return nil, ErrMissingPrefix
+	}
+	input = input[2:]
+	if len(input) == 0 {
+		return nil, ErrEmptyNumber
+	}
+	if len(input) > 1 && input[0] == '0' {
+		return nil, ErrLeadingZero
+	}
+	return input, nil
+}
+
+func wrapTypeError(err error, typ reflect.Type) error {
+	if _, ok := err.(*decError); ok {
+		return &json.UnmarshalTypeError{Value: err.Error(), Type: typ}
+	}
+	return err
+}
+
+func errNonString(typ reflect.Type) error {
+	return &json.UnmarshalTypeError{Value: "non-string", Type: typ}
+}

+ 45 - 0
common/hexutil/json_example_test.go

@@ -0,0 +1,45 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package hexutil_test
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/ethereum/go-ethereum/common/hexutil"
+)
+
+type MyType [5]byte
+
+func (v *MyType) UnmarshalText(input []byte) error {
+	return hexutil.UnmarshalFixedText("MyType", input, v[:])
+}
+
+func (v MyType) String() string {
+	return hexutil.Bytes(v[:]).String()
+}
+
+func ExampleUnmarshalFixedText() {
+	var v1, v2 MyType
+	fmt.Println("v1 error:", json.Unmarshal([]byte(`"0x01"`), &v1))
+	fmt.Println("v2 error:", json.Unmarshal([]byte(`"0x0101010101"`), &v2))
+	fmt.Println("v2:", v2)
+	// Output:
+	// v1 error: hex string has length 2, want 10 for MyType
+	// v2 error: <nil>
+	// v2: 0x0101010101
+}

+ 374 - 0
common/hexutil/json_test.go

@@ -0,0 +1,374 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package hexutil
+
+import (
+	"bytes"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+	"math/big"
+	"testing"
+)
+
+func checkError(t *testing.T, input string, got, want error) bool {
+	if got == nil {
+		if want != nil {
+			t.Errorf("input %s: got no error, want %q", input, want)
+			return false
+		}
+		return true
+	}
+	if want == nil {
+		t.Errorf("input %s: unexpected error %q", input, got)
+	} else if got.Error() != want.Error() {
+		t.Errorf("input %s: got error %q, want %q", input, got, want)
+	}
+	return false
+}
+
+func referenceBig(s string) *big.Int {
+	b, ok := new(big.Int).SetString(s, 16)
+	if !ok {
+		panic("invalid")
+	}
+	return b
+}
+
+func referenceBytes(s string) []byte {
+	b, err := hex.DecodeString(s)
+	if err != nil {
+		panic(err)
+	}
+	return b
+}
+
+var errJSONEOF = errors.New("unexpected end of JSON input")
+
+var unmarshalBytesTests = []unmarshalTest{
+	// invalid encoding
+	{input: "", wantErr: errJSONEOF},
+	{input: "null", wantErr: errNonString(bytesT)},
+	{input: "10", wantErr: errNonString(bytesT)},
+	{input: `"0"`, wantErr: wrapTypeError(ErrMissingPrefix, bytesT)},
+	{input: `"0x0"`, wantErr: wrapTypeError(ErrOddLength, bytesT)},
+	{input: `"0xxx"`, wantErr: wrapTypeError(ErrSyntax, bytesT)},
+	{input: `"0x01zz01"`, wantErr: wrapTypeError(ErrSyntax, bytesT)},
+
+	// valid encoding
+	{input: `""`, want: referenceBytes("")},
+	{input: `"0x"`, want: referenceBytes("")},
+	{input: `"0x02"`, want: referenceBytes("02")},
+	{input: `"0X02"`, want: referenceBytes("02")},
+	{input: `"0xffffffffff"`, want: referenceBytes("ffffffffff")},
+	{
+		input: `"0xffffffffffffffffffffffffffffffffffff"`,
+		want:  referenceBytes("ffffffffffffffffffffffffffffffffffff"),
+	},
+}
+
+func TestUnmarshalBytes(t *testing.T) {
+	for _, test := range unmarshalBytesTests {
+		var v Bytes
+		err := json.Unmarshal([]byte(test.input), &v)
+		if !checkError(t, test.input, err, test.wantErr) {
+			continue
+		}
+		if !bytes.Equal(test.want.([]byte), v) {
+			t.Errorf("input %s: value mismatch: got %x, want %x", test.input, &v, test.want)
+			continue
+		}
+	}
+}
+
+func BenchmarkUnmarshalBytes(b *testing.B) {
+	input := []byte(`"0x123456789abcdef123456789abcdef"`)
+	for i := 0; i < b.N; i++ {
+		var v Bytes
+		if err := v.UnmarshalJSON(input); err != nil {
+			b.Fatal(err)
+		}
+	}
+}
+
+func TestMarshalBytes(t *testing.T) {
+	for _, test := range encodeBytesTests {
+		in := test.input.([]byte)
+		out, err := json.Marshal(Bytes(in))
+		if err != nil {
+			t.Errorf("%x: %v", in, err)
+			continue
+		}
+		if want := `"` + test.want + `"`; string(out) != want {
+			t.Errorf("%x: MarshalJSON output mismatch: got %q, want %q", in, out, want)
+			continue
+		}
+		if out := Bytes(in).String(); out != test.want {
+			t.Errorf("%x: String mismatch: got %q, want %q", in, out, test.want)
+			continue
+		}
+	}
+}
+
+var unmarshalBigTests = []unmarshalTest{
+	// invalid encoding
+	{input: "", wantErr: errJSONEOF},
+	{input: "null", wantErr: errNonString(bigT)},
+	{input: "10", wantErr: errNonString(bigT)},
+	{input: `"0"`, wantErr: wrapTypeError(ErrMissingPrefix, bigT)},
+	{input: `"0x"`, wantErr: wrapTypeError(ErrEmptyNumber, bigT)},
+	{input: `"0x01"`, wantErr: wrapTypeError(ErrLeadingZero, bigT)},
+	{input: `"0xx"`, wantErr: wrapTypeError(ErrSyntax, bigT)},
+	{input: `"0x1zz01"`, wantErr: wrapTypeError(ErrSyntax, bigT)},
+	{
+		input:   `"0x10000000000000000000000000000000000000000000000000000000000000000"`,
+		wantErr: wrapTypeError(ErrBig256Range, bigT),
+	},
+
+	// valid encoding
+	{input: `""`, want: big.NewInt(0)},
+	{input: `"0x0"`, want: big.NewInt(0)},
+	{input: `"0x2"`, want: big.NewInt(0x2)},
+	{input: `"0x2F2"`, want: big.NewInt(0x2f2)},
+	{input: `"0X2F2"`, want: big.NewInt(0x2f2)},
+	{input: `"0x1122aaff"`, want: big.NewInt(0x1122aaff)},
+	{input: `"0xbBb"`, want: big.NewInt(0xbbb)},
+	{input: `"0xfffffffff"`, want: big.NewInt(0xfffffffff)},
+	{
+		input: `"0x112233445566778899aabbccddeeff"`,
+		want:  referenceBig("112233445566778899aabbccddeeff"),
+	},
+	{
+		input: `"0xffffffffffffffffffffffffffffffffffff"`,
+		want:  referenceBig("ffffffffffffffffffffffffffffffffffff"),
+	},
+	{
+		input: `"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"`,
+		want:  referenceBig("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
+	},
+}
+
+func TestUnmarshalBig(t *testing.T) {
+	for _, test := range unmarshalBigTests {
+		var v Big
+		err := json.Unmarshal([]byte(test.input), &v)
+		if !checkError(t, test.input, err, test.wantErr) {
+			continue
+		}
+		if test.want != nil && test.want.(*big.Int).Cmp((*big.Int)(&v)) != 0 {
+			t.Errorf("input %s: value mismatch: got %x, want %x", test.input, (*big.Int)(&v), test.want)
+			continue
+		}
+	}
+}
+
+func BenchmarkUnmarshalBig(b *testing.B) {
+	input := []byte(`"0x123456789abcdef123456789abcdef"`)
+	for i := 0; i < b.N; i++ {
+		var v Big
+		if err := v.UnmarshalJSON(input); err != nil {
+			b.Fatal(err)
+		}
+	}
+}
+
+func TestMarshalBig(t *testing.T) {
+	for _, test := range encodeBigTests {
+		in := test.input.(*big.Int)
+		out, err := json.Marshal((*Big)(in))
+		if err != nil {
+			t.Errorf("%d: %v", in, err)
+			continue
+		}
+		if want := `"` + test.want + `"`; string(out) != want {
+			t.Errorf("%d: MarshalJSON output mismatch: got %q, want %q", in, out, want)
+			continue
+		}
+		if out := (*Big)(in).String(); out != test.want {
+			t.Errorf("%x: String mismatch: got %q, want %q", in, out, test.want)
+			continue
+		}
+	}
+}
+
+var unmarshalUint64Tests = []unmarshalTest{
+	// invalid encoding
+	{input: "", wantErr: errJSONEOF},
+	{input: "null", wantErr: errNonString(uint64T)},
+	{input: "10", wantErr: errNonString(uint64T)},
+	{input: `"0"`, wantErr: wrapTypeError(ErrMissingPrefix, uint64T)},
+	{input: `"0x"`, wantErr: wrapTypeError(ErrEmptyNumber, uint64T)},
+	{input: `"0x01"`, wantErr: wrapTypeError(ErrLeadingZero, uint64T)},
+	{input: `"0xfffffffffffffffff"`, wantErr: wrapTypeError(ErrUint64Range, uint64T)},
+	{input: `"0xx"`, wantErr: wrapTypeError(ErrSyntax, uint64T)},
+	{input: `"0x1zz01"`, wantErr: wrapTypeError(ErrSyntax, uint64T)},
+
+	// valid encoding
+	{input: `""`, want: uint64(0)},
+	{input: `"0x0"`, want: uint64(0)},
+	{input: `"0x2"`, want: uint64(0x2)},
+	{input: `"0x2F2"`, want: uint64(0x2f2)},
+	{input: `"0X2F2"`, want: uint64(0x2f2)},
+	{input: `"0x1122aaff"`, want: uint64(0x1122aaff)},
+	{input: `"0xbbb"`, want: uint64(0xbbb)},
+	{input: `"0xffffffffffffffff"`, want: uint64(0xffffffffffffffff)},
+}
+
+func TestUnmarshalUint64(t *testing.T) {
+	for _, test := range unmarshalUint64Tests {
+		var v Uint64
+		err := json.Unmarshal([]byte(test.input), &v)
+		if !checkError(t, test.input, err, test.wantErr) {
+			continue
+		}
+		if uint64(v) != test.want.(uint64) {
+			t.Errorf("input %s: value mismatch: got %d, want %d", test.input, v, test.want)
+			continue
+		}
+	}
+}
+
+func BenchmarkUnmarshalUint64(b *testing.B) {
+	input := []byte(`"0x123456789abcdf"`)
+	for i := 0; i < b.N; i++ {
+		var v Uint64
+		v.UnmarshalJSON(input)
+	}
+}
+
+func TestMarshalUint64(t *testing.T) {
+	for _, test := range encodeUint64Tests {
+		in := test.input.(uint64)
+		out, err := json.Marshal(Uint64(in))
+		if err != nil {
+			t.Errorf("%d: %v", in, err)
+			continue
+		}
+		if want := `"` + test.want + `"`; string(out) != want {
+			t.Errorf("%d: MarshalJSON output mismatch: got %q, want %q", in, out, want)
+			continue
+		}
+		if out := (Uint64)(in).String(); out != test.want {
+			t.Errorf("%x: String mismatch: got %q, want %q", in, out, test.want)
+			continue
+		}
+	}
+}
+
+func TestMarshalUint(t *testing.T) {
+	for _, test := range encodeUintTests {
+		in := test.input.(uint)
+		out, err := json.Marshal(Uint(in))
+		if err != nil {
+			t.Errorf("%d: %v", in, err)
+			continue
+		}
+		if want := `"` + test.want + `"`; string(out) != want {
+			t.Errorf("%d: MarshalJSON output mismatch: got %q, want %q", in, out, want)
+			continue
+		}
+		if out := (Uint)(in).String(); out != test.want {
+			t.Errorf("%x: String mismatch: got %q, want %q", in, out, test.want)
+			continue
+		}
+	}
+}
+
+var (
+	// These are variables (not constants) to avoid constant overflow
+	// checks in the compiler on 32bit platforms.
+	maxUint33bits = uint64(^uint32(0)) + 1
+	maxUint64bits = ^uint64(0)
+)
+
+var unmarshalUintTests = []unmarshalTest{
+	// invalid encoding
+	{input: "", wantErr: errJSONEOF},
+	{input: "null", wantErr: errNonString(uintT)},
+	{input: "10", wantErr: errNonString(uintT)},
+	{input: `"0"`, wantErr: wrapTypeError(ErrMissingPrefix, uintT)},
+	{input: `"0x"`, wantErr: wrapTypeError(ErrEmptyNumber, uintT)},
+	{input: `"0x01"`, wantErr: wrapTypeError(ErrLeadingZero, uintT)},
+	{input: `"0x100000000"`, want: uint(maxUint33bits), wantErr32bit: wrapTypeError(ErrUintRange, uintT)},
+	{input: `"0xfffffffffffffffff"`, wantErr: wrapTypeError(ErrUintRange, uintT)},
+	{input: `"0xx"`, wantErr: wrapTypeError(ErrSyntax, uintT)},
+	{input: `"0x1zz01"`, wantErr: wrapTypeError(ErrSyntax, uintT)},
+
+	// valid encoding
+	{input: `""`, want: uint(0)},
+	{input: `"0x0"`, want: uint(0)},
+	{input: `"0x2"`, want: uint(0x2)},
+	{input: `"0x2F2"`, want: uint(0x2f2)},
+	{input: `"0X2F2"`, want: uint(0x2f2)},
+	{input: `"0x1122aaff"`, want: uint(0x1122aaff)},
+	{input: `"0xbbb"`, want: uint(0xbbb)},
+	{input: `"0xffffffff"`, want: uint(0xffffffff)},
+	{input: `"0xffffffffffffffff"`, want: uint(maxUint64bits), wantErr32bit: wrapTypeError(ErrUintRange, uintT)},
+}
+
+func TestUnmarshalUint(t *testing.T) {
+	for _, test := range unmarshalUintTests {
+		var v Uint
+		err := json.Unmarshal([]byte(test.input), &v)
+		if uintBits == 32 && test.wantErr32bit != nil {
+			checkError(t, test.input, err, test.wantErr32bit)
+			continue
+		}
+		if !checkError(t, test.input, err, test.wantErr) {
+			continue
+		}
+		if uint(v) != test.want.(uint) {
+			t.Errorf("input %s: value mismatch: got %d, want %d", test.input, v, test.want)
+			continue
+		}
+	}
+}
+
+func TestUnmarshalFixedUnprefixedText(t *testing.T) {
+	tests := []struct {
+		input   string
+		want    []byte
+		wantErr error
+	}{
+		{input: "0x2", wantErr: ErrOddLength},
+		{input: "2", wantErr: ErrOddLength},
+		{input: "4444", wantErr: errors.New("hex string has length 4, want 8 for x")},
+		{input: "4444", wantErr: errors.New("hex string has length 4, want 8 for x")},
+		// check that output is not modified for partially correct input
+		{input: "444444gg", wantErr: ErrSyntax, want: []byte{0, 0, 0, 0}},
+		{input: "0x444444gg", wantErr: ErrSyntax, want: []byte{0, 0, 0, 0}},
+		// valid inputs
+		{input: "44444444", want: []byte{0x44, 0x44, 0x44, 0x44}},
+		{input: "0x44444444", want: []byte{0x44, 0x44, 0x44, 0x44}},
+	}
+
+	for _, test := range tests {
+		out := make([]byte, 4)
+		err := UnmarshalFixedUnprefixedText("x", []byte(test.input), out)
+		switch {
+		case err == nil && test.wantErr != nil:
+			t.Errorf("%q: got no error, expected %q", test.input, test.wantErr)
+		case err != nil && test.wantErr == nil:
+			t.Errorf("%q: unexpected error %q", test.input, err)
+		case err != nil && err.Error() != test.wantErr.Error():
+			t.Errorf("%q: error mismatch: got %q, want %q", test.input, err, test.wantErr)
+		}
+		if test.want != nil && !bytes.Equal(out, test.want) {
+			t.Errorf("%q: output mismatch: got %x, want %x", test.input, out, test.want)
+		}
+	}
+}

+ 259 - 0
common/math/big.go

@@ -0,0 +1,259 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// Package math provides integer math utilities.
+package math
+
+import (
+	"fmt"
+	"math/big"
+)
+
+// Various big integer limit values.
+var (
+	tt255     = BigPow(2, 255)
+	tt256     = BigPow(2, 256)
+	tt256m1   = new(big.Int).Sub(tt256, big.NewInt(1))
+	tt63      = BigPow(2, 63)
+	MaxBig256 = new(big.Int).Set(tt256m1)
+	MaxBig63  = new(big.Int).Sub(tt63, big.NewInt(1))
+)
+
+const (
+	// number of bits in a big.Word
+	wordBits = 32 << (uint64(^big.Word(0)) >> 63)
+	// number of bytes in a big.Word
+	wordBytes = wordBits / 8
+)
+
+// HexOrDecimal256 marshals big.Int as hex or decimal.
+type HexOrDecimal256 big.Int
+
+// NewHexOrDecimal256 creates a new HexOrDecimal256
+func NewHexOrDecimal256(x int64) *HexOrDecimal256 {
+	b := big.NewInt(x)
+	h := HexOrDecimal256(*b)
+	return &h
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (i *HexOrDecimal256) UnmarshalText(input []byte) error {
+	bigint, ok := ParseBig256(string(input))
+	if !ok {
+		return fmt.Errorf("invalid hex or decimal integer %q", input)
+	}
+	*i = HexOrDecimal256(*bigint)
+	return nil
+}
+
+// MarshalText implements encoding.TextMarshaler.
+func (i *HexOrDecimal256) MarshalText() ([]byte, error) {
+	if i == nil {
+		return []byte("0x0"), nil
+	}
+	return []byte(fmt.Sprintf("%#x", (*big.Int)(i))), nil
+}
+
+// Decimal256 unmarshals big.Int as a decimal string. When unmarshalling,
+// it however accepts either "0x"-prefixed (hex encoded) or non-prefixed (decimal)
+type Decimal256 big.Int
+
+// NewHexOrDecimal256 creates a new Decimal256
+func NewDecimal256(x int64) *Decimal256 {
+	b := big.NewInt(x)
+	d := Decimal256(*b)
+	return &d
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (i *Decimal256) UnmarshalText(input []byte) error {
+	bigint, ok := ParseBig256(string(input))
+	if !ok {
+		return fmt.Errorf("invalid hex or decimal integer %q", input)
+	}
+	*i = Decimal256(*bigint)
+	return nil
+}
+
+// MarshalText implements encoding.TextMarshaler.
+func (i *Decimal256) MarshalText() ([]byte, error) {
+	return []byte(i.String()), nil
+}
+
+// String implements Stringer.
+func (i *Decimal256) String() string {
+	if i == nil {
+		return "0"
+	}
+	return fmt.Sprintf("%#d", (*big.Int)(i))
+}
+
+// ParseBig256 parses s as a 256 bit integer in decimal or hexadecimal syntax.
+// Leading zeros are accepted. The empty string parses as zero.
+func ParseBig256(s string) (*big.Int, bool) {
+	if s == "" {
+		return new(big.Int), true
+	}
+	var bigint *big.Int
+	var ok bool
+	if len(s) >= 2 && (s[:2] == "0x" || s[:2] == "0X") {
+		bigint, ok = new(big.Int).SetString(s[2:], 16)
+	} else {
+		bigint, ok = new(big.Int).SetString(s, 10)
+	}
+	if ok && bigint.BitLen() > 256 {
+		bigint, ok = nil, false
+	}
+	return bigint, ok
+}
+
+// MustParseBig256 parses s as a 256 bit big integer and panics if the string is invalid.
+func MustParseBig256(s string) *big.Int {
+	v, ok := ParseBig256(s)
+	if !ok {
+		panic("invalid 256 bit integer: " + s)
+	}
+	return v
+}
+
+// BigPow returns a ** b as a big integer.
+func BigPow(a, b int64) *big.Int {
+	r := big.NewInt(a)
+	return r.Exp(r, big.NewInt(b), nil)
+}
+
+// BigMax returns the larger of x or y.
+func BigMax(x, y *big.Int) *big.Int {
+	if x.Cmp(y) < 0 {
+		return y
+	}
+	return x
+}
+
+// BigMin returns the smaller of x or y.
+func BigMin(x, y *big.Int) *big.Int {
+	if x.Cmp(y) > 0 {
+		return y
+	}
+	return x
+}
+
+// FirstBitSet returns the index of the first 1 bit in v, counting from LSB.
+func FirstBitSet(v *big.Int) int {
+	for i := 0; i < v.BitLen(); i++ {
+		if v.Bit(i) > 0 {
+			return i
+		}
+	}
+	return v.BitLen()
+}
+
+// PaddedBigBytes encodes a big integer as a big-endian byte slice. The length
+// of the slice is at least n bytes.
+func PaddedBigBytes(bigint *big.Int, n int) []byte {
+	if bigint.BitLen()/8 >= n {
+		return bigint.Bytes()
+	}
+	ret := make([]byte, n)
+	ReadBits(bigint, ret)
+	return ret
+}
+
+// bigEndianByteAt returns the byte at position n,
+// in Big-Endian encoding
+// So n==0 returns the least significant byte
+func bigEndianByteAt(bigint *big.Int, n int) byte {
+	words := bigint.Bits()
+	// Check word-bucket the byte will reside in
+	i := n / wordBytes
+	if i >= len(words) {
+		return byte(0)
+	}
+	word := words[i]
+	// Offset of the byte
+	shift := 8 * uint(n%wordBytes)
+
+	return byte(word >> shift)
+}
+
+// Byte returns the byte at position n,
+// with the supplied padlength in Little-Endian encoding.
+// n==0 returns the MSB
+// Example: bigint '5', padlength 32, n=31 => 5
+func Byte(bigint *big.Int, padlength, n int) byte {
+	if n >= padlength {
+		return byte(0)
+	}
+	return bigEndianByteAt(bigint, padlength-1-n)
+}
+
+// ReadBits encodes the absolute value of bigint as big-endian bytes. Callers must ensure
+// that buf has enough space. If buf is too short the result will be incomplete.
+func ReadBits(bigint *big.Int, buf []byte) {
+	i := len(buf)
+	for _, d := range bigint.Bits() {
+		for j := 0; j < wordBytes && i > 0; j++ {
+			i--
+			buf[i] = byte(d)
+			d >>= 8
+		}
+	}
+}
+
+// U256 encodes as a 256 bit two's complement number. This operation is destructive.
+func U256(x *big.Int) *big.Int {
+	return x.And(x, tt256m1)
+}
+
+// U256Bytes converts a big Int into a 256bit EVM number.
+// This operation is destructive.
+func U256Bytes(n *big.Int) []byte {
+	return PaddedBigBytes(U256(n), 32)
+}
+
+// S256 interprets x as a two's complement number.
+// x must not exceed 256 bits (the result is undefined if it does) and is not modified.
+//
+//   S256(0)        = 0
+//   S256(1)        = 1
+//   S256(2**255)   = -2**255
+//   S256(2**256-1) = -1
+func S256(x *big.Int) *big.Int {
+	if x.Cmp(tt255) < 0 {
+		return x
+	}
+	return new(big.Int).Sub(x, tt256)
+}
+
+// Exp implements exponentiation by squaring.
+// Exp returns a newly-allocated big integer and does not change
+// base or exponent. The result is truncated to 256 bits.
+//
+// Courtesy @karalabe and @chfast
+func Exp(base, exponent *big.Int) *big.Int {
+	result := big.NewInt(1)
+
+	for _, word := range exponent.Bits() {
+		for i := 0; i < wordBits; i++ {
+			if word&1 == 1 {
+				U256(result.Mul(result, base))
+			}
+			U256(base.Mul(base, base))
+			word >>= 1
+		}
+	}
+	return result
+}

+ 327 - 0
common/math/big_test.go

@@ -0,0 +1,327 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package math
+
+import (
+	"bytes"
+	"encoding/hex"
+	"math/big"
+	"testing"
+
+	"github.com/ethereum/go-ethereum/common"
+)
+
+func TestHexOrDecimal256(t *testing.T) {
+	tests := []struct {
+		input string
+		num   *big.Int
+		ok    bool
+	}{
+		{"", big.NewInt(0), true},
+		{"0", big.NewInt(0), true},
+		{"0x0", big.NewInt(0), true},
+		{"12345678", big.NewInt(12345678), true},
+		{"0x12345678", big.NewInt(0x12345678), true},
+		{"0X12345678", big.NewInt(0x12345678), true},
+		// Tests for leading zero behaviour:
+		{"0123456789", big.NewInt(123456789), true}, // note: not octal
+		{"00", big.NewInt(0), true},
+		{"0x00", big.NewInt(0), true},
+		{"0x012345678abc", big.NewInt(0x12345678abc), true},
+		// Invalid syntax:
+		{"abcdef", nil, false},
+		{"0xgg", nil, false},
+		// Larger than 256 bits:
+		{"115792089237316195423570985008687907853269984665640564039457584007913129639936", nil, false},
+	}
+	for _, test := range tests {
+		var num HexOrDecimal256
+		err := num.UnmarshalText([]byte(test.input))
+		if (err == nil) != test.ok {
+			t.Errorf("ParseBig(%q) -> (err == nil) == %t, want %t", test.input, err == nil, test.ok)
+			continue
+		}
+		if test.num != nil && (*big.Int)(&num).Cmp(test.num) != 0 {
+			t.Errorf("ParseBig(%q) -> %d, want %d", test.input, (*big.Int)(&num), test.num)
+		}
+	}
+}
+
+func TestMustParseBig256(t *testing.T) {
+	defer func() {
+		if recover() == nil {
+			t.Error("MustParseBig should've panicked")
+		}
+	}()
+	MustParseBig256("ggg")
+}
+
+func TestBigMax(t *testing.T) {
+	a := big.NewInt(10)
+	b := big.NewInt(5)
+
+	max1 := BigMax(a, b)
+	if max1 != a {
+		t.Errorf("Expected %d got %d", a, max1)
+	}
+
+	max2 := BigMax(b, a)
+	if max2 != a {
+		t.Errorf("Expected %d got %d", a, max2)
+	}
+}
+
+func TestBigMin(t *testing.T) {
+	a := big.NewInt(10)
+	b := big.NewInt(5)
+
+	min1 := BigMin(a, b)
+	if min1 != b {
+		t.Errorf("Expected %d got %d", b, min1)
+	}
+
+	min2 := BigMin(b, a)
+	if min2 != b {
+		t.Errorf("Expected %d got %d", b, min2)
+	}
+}
+
+func TestFirstBigSet(t *testing.T) {
+	tests := []struct {
+		num *big.Int
+		ix  int
+	}{
+		{big.NewInt(0), 0},
+		{big.NewInt(1), 0},
+		{big.NewInt(2), 1},
+		{big.NewInt(0x100), 8},
+	}
+	for _, test := range tests {
+		if ix := FirstBitSet(test.num); ix != test.ix {
+			t.Errorf("FirstBitSet(b%b) = %d, want %d", test.num, ix, test.ix)
+		}
+	}
+}
+
+func TestPaddedBigBytes(t *testing.T) {
+	tests := []struct {
+		num    *big.Int
+		n      int
+		result []byte
+	}{
+		{num: big.NewInt(0), n: 4, result: []byte{0, 0, 0, 0}},
+		{num: big.NewInt(1), n: 4, result: []byte{0, 0, 0, 1}},
+		{num: big.NewInt(512), n: 4, result: []byte{0, 0, 2, 0}},
+		{num: BigPow(2, 32), n: 4, result: []byte{1, 0, 0, 0, 0}},
+	}
+	for _, test := range tests {
+		if result := PaddedBigBytes(test.num, test.n); !bytes.Equal(result, test.result) {
+			t.Errorf("PaddedBigBytes(%d, %d) = %v, want %v", test.num, test.n, result, test.result)
+		}
+	}
+}
+
+func BenchmarkPaddedBigBytesLargePadding(b *testing.B) {
+	bigint := MustParseBig256("123456789123456789123456789123456789")
+	for i := 0; i < b.N; i++ {
+		PaddedBigBytes(bigint, 200)
+	}
+}
+
+func BenchmarkPaddedBigBytesSmallPadding(b *testing.B) {
+	bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC")
+	for i := 0; i < b.N; i++ {
+		PaddedBigBytes(bigint, 5)
+	}
+}
+
+func BenchmarkPaddedBigBytesSmallOnePadding(b *testing.B) {
+	bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC")
+	for i := 0; i < b.N; i++ {
+		PaddedBigBytes(bigint, 32)
+	}
+}
+
+func BenchmarkByteAtBrandNew(b *testing.B) {
+	bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC")
+	for i := 0; i < b.N; i++ {
+		bigEndianByteAt(bigint, 15)
+	}
+}
+
+func BenchmarkByteAt(b *testing.B) {
+	bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC")
+	for i := 0; i < b.N; i++ {
+		bigEndianByteAt(bigint, 15)
+	}
+}
+
+func BenchmarkByteAtOld(b *testing.B) {
+
+	bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC")
+	for i := 0; i < b.N; i++ {
+		PaddedBigBytes(bigint, 32)
+	}
+}
+
+func TestReadBits(t *testing.T) {
+	check := func(input string) {
+		want, _ := hex.DecodeString(input)
+		int, _ := new(big.Int).SetString(input, 16)
+		buf := make([]byte, len(want))
+		ReadBits(int, buf)
+		if !bytes.Equal(buf, want) {
+			t.Errorf("have: %x\nwant: %x", buf, want)
+		}
+	}
+	check("000000000000000000000000000000000000000000000000000000FEFCF3F8F0")
+	check("0000000000012345000000000000000000000000000000000000FEFCF3F8F0")
+	check("18F8F8F1000111000110011100222004330052300000000000000000FEFCF3F8F0")
+}
+
+func TestU256(t *testing.T) {
+	tests := []struct{ x, y *big.Int }{
+		{x: big.NewInt(0), y: big.NewInt(0)},
+		{x: big.NewInt(1), y: big.NewInt(1)},
+		{x: BigPow(2, 255), y: BigPow(2, 255)},
+		{x: BigPow(2, 256), y: big.NewInt(0)},
+		{x: new(big.Int).Add(BigPow(2, 256), big.NewInt(1)), y: big.NewInt(1)},
+		// negative values
+		{x: big.NewInt(-1), y: new(big.Int).Sub(BigPow(2, 256), big.NewInt(1))},
+		{x: big.NewInt(-2), y: new(big.Int).Sub(BigPow(2, 256), big.NewInt(2))},
+		{x: BigPow(2, -255), y: big.NewInt(1)},
+	}
+	for _, test := range tests {
+		if y := U256(new(big.Int).Set(test.x)); y.Cmp(test.y) != 0 {
+			t.Errorf("U256(%x) = %x, want %x", test.x, y, test.y)
+		}
+	}
+}
+
+func TestU256Bytes(t *testing.T) {
+	ubytes := make([]byte, 32)
+	ubytes[31] = 1
+
+	unsigned := U256Bytes(big.NewInt(1))
+	if !bytes.Equal(unsigned, ubytes) {
+		t.Errorf("expected %x got %x", ubytes, unsigned)
+	}
+}
+
+func TestBigEndianByteAt(t *testing.T) {
+	tests := []struct {
+		x   string
+		y   int
+		exp byte
+	}{
+		{"00", 0, 0x00},
+		{"01", 1, 0x00},
+		{"00", 1, 0x00},
+		{"01", 0, 0x01},
+		{"0000000000000000000000000000000000000000000000000000000000102030", 0, 0x30},
+		{"0000000000000000000000000000000000000000000000000000000000102030", 1, 0x20},
+		{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 31, 0xAB},
+		{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 32, 0x00},
+		{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 500, 0x00},
+	}
+	for _, test := range tests {
+		v := new(big.Int).SetBytes(common.Hex2Bytes(test.x))
+		actual := bigEndianByteAt(v, test.y)
+		if actual != test.exp {
+			t.Fatalf("Expected  [%v] %v:th byte to be %v, was %v.", test.x, test.y, test.exp, actual)
+		}
+
+	}
+}
+func TestLittleEndianByteAt(t *testing.T) {
+	tests := []struct {
+		x   string
+		y   int
+		exp byte
+	}{
+		{"00", 0, 0x00},
+		{"01", 1, 0x00},
+		{"00", 1, 0x00},
+		{"01", 0, 0x00},
+		{"0000000000000000000000000000000000000000000000000000000000102030", 0, 0x00},
+		{"0000000000000000000000000000000000000000000000000000000000102030", 1, 0x00},
+		{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 31, 0x00},
+		{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 32, 0x00},
+		{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 0, 0xAB},
+		{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 1, 0xCD},
+		{"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", 0, 0x00},
+		{"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", 1, 0xCD},
+		{"0000000000000000000000000000000000000000000000000000000000102030", 31, 0x30},
+		{"0000000000000000000000000000000000000000000000000000000000102030", 30, 0x20},
+		{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 32, 0x0},
+		{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 31, 0xFF},
+		{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0xFFFF, 0x0},
+	}
+	for _, test := range tests {
+		v := new(big.Int).SetBytes(common.Hex2Bytes(test.x))
+		actual := Byte(v, 32, test.y)
+		if actual != test.exp {
+			t.Fatalf("Expected  [%v] %v:th byte to be %v, was %v.", test.x, test.y, test.exp, actual)
+		}
+
+	}
+}
+
+func TestS256(t *testing.T) {
+	tests := []struct{ x, y *big.Int }{
+		{x: big.NewInt(0), y: big.NewInt(0)},
+		{x: big.NewInt(1), y: big.NewInt(1)},
+		{x: big.NewInt(2), y: big.NewInt(2)},
+		{
+			x: new(big.Int).Sub(BigPow(2, 255), big.NewInt(1)),
+			y: new(big.Int).Sub(BigPow(2, 255), big.NewInt(1)),
+		},
+		{
+			x: BigPow(2, 255),
+			y: new(big.Int).Neg(BigPow(2, 255)),
+		},
+		{
+			x: new(big.Int).Sub(BigPow(2, 256), big.NewInt(1)),
+			y: big.NewInt(-1),
+		},
+		{
+			x: new(big.Int).Sub(BigPow(2, 256), big.NewInt(2)),
+			y: big.NewInt(-2),
+		},
+	}
+	for _, test := range tests {
+		if y := S256(test.x); y.Cmp(test.y) != 0 {
+			t.Errorf("S256(%x) = %x, want %x", test.x, y, test.y)
+		}
+	}
+}
+
+func TestExp(t *testing.T) {
+	tests := []struct{ base, exponent, result *big.Int }{
+		{base: big.NewInt(0), exponent: big.NewInt(0), result: big.NewInt(1)},
+		{base: big.NewInt(1), exponent: big.NewInt(0), result: big.NewInt(1)},
+		{base: big.NewInt(1), exponent: big.NewInt(1), result: big.NewInt(1)},
+		{base: big.NewInt(1), exponent: big.NewInt(2), result: big.NewInt(1)},
+		{base: big.NewInt(3), exponent: big.NewInt(144), result: MustParseBig256("507528786056415600719754159741696356908742250191663887263627442114881")},
+		{base: big.NewInt(2), exponent: big.NewInt(255), result: MustParseBig256("57896044618658097711785492504343953926634992332820282019728792003956564819968")},
+	}
+	for _, test := range tests {
+		if result := Exp(test.base, test.exponent); result.Cmp(test.result) != 0 {
+			t.Errorf("Exp(%d, %d) = %d, want %d", test.base, test.exponent, result, test.result)
+		}
+	}
+}

+ 98 - 0
common/math/integer.go

@@ -0,0 +1,98 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package math
+
+import (
+	"fmt"
+	"math/bits"
+	"strconv"
+)
+
+// Integer limit values.
+const (
+	MaxInt8   = 1<<7 - 1
+	MinInt8   = -1 << 7
+	MaxInt16  = 1<<15 - 1
+	MinInt16  = -1 << 15
+	MaxInt32  = 1<<31 - 1
+	MinInt32  = -1 << 31
+	MaxInt64  = 1<<63 - 1
+	MinInt64  = -1 << 63
+	MaxUint8  = 1<<8 - 1
+	MaxUint16 = 1<<16 - 1
+	MaxUint32 = 1<<32 - 1
+	MaxUint64 = 1<<64 - 1
+)
+
+// HexOrDecimal64 marshals uint64 as hex or decimal.
+type HexOrDecimal64 uint64
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (i *HexOrDecimal64) UnmarshalText(input []byte) error {
+	int, ok := ParseUint64(string(input))
+	if !ok {
+		return fmt.Errorf("invalid hex or decimal integer %q", input)
+	}
+	*i = HexOrDecimal64(int)
+	return nil
+}
+
+// MarshalText implements encoding.TextMarshaler.
+func (i HexOrDecimal64) MarshalText() ([]byte, error) {
+	return []byte(fmt.Sprintf("%#x", uint64(i))), nil
+}
+
+// ParseUint64 parses s as an integer in decimal or hexadecimal syntax.
+// Leading zeros are accepted. The empty string parses as zero.
+func ParseUint64(s string) (uint64, bool) {
+	if s == "" {
+		return 0, true
+	}
+	if len(s) >= 2 && (s[:2] == "0x" || s[:2] == "0X") {
+		v, err := strconv.ParseUint(s[2:], 16, 64)
+		return v, err == nil
+	}
+	v, err := strconv.ParseUint(s, 10, 64)
+	return v, err == nil
+}
+
+// MustParseUint64 parses s as an integer and panics if the string is invalid.
+func MustParseUint64(s string) uint64 {
+	v, ok := ParseUint64(s)
+	if !ok {
+		panic("invalid unsigned 64 bit integer: " + s)
+	}
+	return v
+}
+
+// SafeSub returns x-y and checks for overflow.
+func SafeSub(x, y uint64) (uint64, bool) {
+	diff, borrowOut := bits.Sub64(x, y, 0)
+	return diff, borrowOut != 0
+}
+
+// SafeAdd returns x+y and checks for overflow.
+func SafeAdd(x, y uint64) (uint64, bool) {
+	sum, carryOut := bits.Add64(x, y, 0)
+	return sum, carryOut != 0
+}
+
+// SafeMul returns x*y and checks for overflow.
+func SafeMul(x, y uint64) (uint64, bool) {
+	hi, lo := bits.Mul64(x, y)
+	return lo, hi != 0
+}

+ 116 - 0
common/math/integer_test.go

@@ -0,0 +1,116 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package math
+
+import (
+	"testing"
+)
+
+type operation byte
+
+const (
+	sub operation = iota
+	add
+	mul
+)
+
+func TestOverflow(t *testing.T) {
+	for i, test := range []struct {
+		x        uint64
+		y        uint64
+		overflow bool
+		op       operation
+	}{
+		// add operations
+		{MaxUint64, 1, true, add},
+		{MaxUint64 - 1, 1, false, add},
+
+		// sub operations
+		{0, 1, true, sub},
+		{0, 0, false, sub},
+
+		// mul operations
+		{0, 0, false, mul},
+		{10, 10, false, mul},
+		{MaxUint64, 2, true, mul},
+		{MaxUint64, 1, false, mul},
+	} {
+		var overflows bool
+		switch test.op {
+		case sub:
+			_, overflows = SafeSub(test.x, test.y)
+		case add:
+			_, overflows = SafeAdd(test.x, test.y)
+		case mul:
+			_, overflows = SafeMul(test.x, test.y)
+		}
+
+		if test.overflow != overflows {
+			t.Errorf("%d failed. Expected test to be %v, got %v", i, test.overflow, overflows)
+		}
+	}
+}
+
+func TestHexOrDecimal64(t *testing.T) {
+	tests := []struct {
+		input string
+		num   uint64
+		ok    bool
+	}{
+		{"", 0, true},
+		{"0", 0, true},
+		{"0x0", 0, true},
+		{"12345678", 12345678, true},
+		{"0x12345678", 0x12345678, true},
+		{"0X12345678", 0x12345678, true},
+		// Tests for leading zero behaviour:
+		{"0123456789", 123456789, true}, // note: not octal
+		{"0x00", 0, true},
+		{"0x012345678abc", 0x12345678abc, true},
+		// Invalid syntax:
+		{"abcdef", 0, false},
+		{"0xgg", 0, false},
+		// Doesn't fit into 64 bits:
+		{"18446744073709551617", 0, false},
+	}
+	for _, test := range tests {
+		var num HexOrDecimal64
+		err := num.UnmarshalText([]byte(test.input))
+		if (err == nil) != test.ok {
+			t.Errorf("ParseUint64(%q) -> (err == nil) = %t, want %t", test.input, err == nil, test.ok)
+			continue
+		}
+		if err == nil && uint64(num) != test.num {
+			t.Errorf("ParseUint64(%q) -> %d, want %d", test.input, num, test.num)
+		}
+	}
+}
+
+func TestMustParseUint64(t *testing.T) {
+	if v := MustParseUint64("12345"); v != 12345 {
+		t.Errorf(`MustParseUint64("12345") = %d, want 12345`, v)
+	}
+}
+
+func TestMustParseUint64Panic(t *testing.T) {
+	defer func() {
+		if recover() == nil {
+			t.Error("MustParseBig should've panicked")
+		}
+	}()
+	MustParseUint64("ggg")
+}

+ 127 - 0
common/mclock/mclock.go

@@ -0,0 +1,127 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// Package mclock is a wrapper for a monotonic clock source
+package mclock
+
+import (
+	"time"
+
+	_ "unsafe" // for go:linkname
+)
+
+//go:noescape
+//go:linkname nanotime runtime.nanotime
+func nanotime() int64
+
+// AbsTime represents absolute monotonic time.
+type AbsTime int64
+
+// Now returns the current absolute monotonic time.
+func Now() AbsTime {
+	return AbsTime(nanotime())
+}
+
+// Add returns t + d as absolute time.
+func (t AbsTime) Add(d time.Duration) AbsTime {
+	return t + AbsTime(d)
+}
+
+// Sub returns t - t2 as a duration.
+func (t AbsTime) Sub(t2 AbsTime) time.Duration {
+	return time.Duration(t - t2)
+}
+
+// The Clock interface makes it possible to replace the monotonic system clock with
+// a simulated clock.
+type Clock interface {
+	Now() AbsTime
+	Sleep(time.Duration)
+	NewTimer(time.Duration) ChanTimer
+	After(time.Duration) <-chan AbsTime
+	AfterFunc(d time.Duration, f func()) Timer
+}
+
+// Timer is a cancellable event created by AfterFunc.
+type Timer interface {
+	// Stop cancels the timer. It returns false if the timer has already
+	// expired or been stopped.
+	Stop() bool
+}
+
+// ChanTimer is a cancellable event created by NewTimer.
+type ChanTimer interface {
+	Timer
+
+	// The channel returned by C receives a value when the timer expires.
+	C() <-chan AbsTime
+	// Reset reschedules the timer with a new timeout.
+	// It should be invoked only on stopped or expired timers with drained channels.
+	Reset(time.Duration)
+}
+
+// System implements Clock using the system clock.
+type System struct{}
+
+// Now returns the current monotonic time.
+func (c System) Now() AbsTime {
+	return Now()
+}
+
+// Sleep blocks for the given duration.
+func (c System) Sleep(d time.Duration) {
+	time.Sleep(d)
+}
+
+// NewTimer creates a timer which can be rescheduled.
+func (c System) NewTimer(d time.Duration) ChanTimer {
+	ch := make(chan AbsTime, 1)
+	t := time.AfterFunc(d, func() {
+		// This send is non-blocking because that's how time.Timer
+		// behaves. It doesn't matter in the happy case, but does
+		// when Reset is misused.
+		select {
+		case ch <- c.Now():
+		default:
+		}
+	})
+	return &systemTimer{t, ch}
+}
+
+// After returns a channel which receives the current time after d has elapsed.
+func (c System) After(d time.Duration) <-chan AbsTime {
+	ch := make(chan AbsTime, 1)
+	time.AfterFunc(d, func() { ch <- c.Now() })
+	return ch
+}
+
+// AfterFunc runs f on a new goroutine after the duration has elapsed.
+func (c System) AfterFunc(d time.Duration, f func()) Timer {
+	return time.AfterFunc(d, f)
+}
+
+type systemTimer struct {
+	*time.Timer
+	ch <-chan AbsTime
+}
+
+func (st *systemTimer) Reset(d time.Duration) {
+	st.Timer.Reset(d)
+}
+
+func (st *systemTimer) C() <-chan AbsTime {
+	return st.ch
+}

+ 1 - 0
common/mclock/mclock.s

@@ -0,0 +1 @@
+// This file exists in order to be able to use go:linkname.

+ 209 - 0
common/mclock/simclock.go

@@ -0,0 +1,209 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package mclock
+
+import (
+	"container/heap"
+	"sync"
+	"time"
+)
+
+// Simulated implements a virtual Clock for reproducible time-sensitive tests. It
+// simulates a scheduler on a virtual timescale where actual processing takes zero time.
+//
+// The virtual clock doesn't advance on its own, call Run to advance it and execute timers.
+// Since there is no way to influence the Go scheduler, testing timeout behaviour involving
+// goroutines needs special care. A good way to test such timeouts is as follows: First
+// perform the action that is supposed to time out. Ensure that the timer you want to test
+// is created. Then run the clock until after the timeout. Finally observe the effect of
+// the timeout using a channel or semaphore.
+type Simulated struct {
+	now       AbsTime
+	scheduled simTimerHeap
+	mu        sync.RWMutex
+	cond      *sync.Cond
+}
+
+// simTimer implements ChanTimer on the virtual clock.
+type simTimer struct {
+	at    AbsTime
+	index int // position in s.scheduled
+	s     *Simulated
+	do    func()
+	ch    <-chan AbsTime
+}
+
+func (s *Simulated) init() {
+	if s.cond == nil {
+		s.cond = sync.NewCond(&s.mu)
+	}
+}
+
+// Run moves the clock by the given duration, executing all timers before that duration.
+func (s *Simulated) Run(d time.Duration) {
+	s.mu.Lock()
+	s.init()
+
+	end := s.now + AbsTime(d)
+	var do []func()
+	for len(s.scheduled) > 0 && s.scheduled[0].at <= end {
+		ev := heap.Pop(&s.scheduled).(*simTimer)
+		do = append(do, ev.do)
+	}
+	s.now = end
+	s.mu.Unlock()
+
+	for _, fn := range do {
+		fn()
+	}
+}
+
+// ActiveTimers returns the number of timers that haven't fired.
+func (s *Simulated) ActiveTimers() int {
+	s.mu.RLock()
+	defer s.mu.RUnlock()
+
+	return len(s.scheduled)
+}
+
+// WaitForTimers waits until the clock has at least n scheduled timers.
+func (s *Simulated) WaitForTimers(n int) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	s.init()
+
+	for len(s.scheduled) < n {
+		s.cond.Wait()
+	}
+}
+
+// Now returns the current virtual time.
+func (s *Simulated) Now() AbsTime {
+	s.mu.RLock()
+	defer s.mu.RUnlock()
+
+	return s.now
+}
+
+// Sleep blocks until the clock has advanced by d.
+func (s *Simulated) Sleep(d time.Duration) {
+	<-s.After(d)
+}
+
+// NewTimer creates a timer which fires when the clock has advanced by d.
+func (s *Simulated) NewTimer(d time.Duration) ChanTimer {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	ch := make(chan AbsTime, 1)
+	var timer *simTimer
+	timer = s.schedule(d, func() { ch <- timer.at })
+	timer.ch = ch
+	return timer
+}
+
+// After returns a channel which receives the current time after the clock
+// has advanced by d.
+func (s *Simulated) After(d time.Duration) <-chan AbsTime {
+	return s.NewTimer(d).C()
+}
+
+// AfterFunc runs fn after the clock has advanced by d. Unlike with the system
+// clock, fn runs on the goroutine that calls Run.
+func (s *Simulated) AfterFunc(d time.Duration, fn func()) Timer {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	return s.schedule(d, fn)
+}
+
+func (s *Simulated) schedule(d time.Duration, fn func()) *simTimer {
+	s.init()
+
+	at := s.now + AbsTime(d)
+	ev := &simTimer{do: fn, at: at, s: s}
+	heap.Push(&s.scheduled, ev)
+	s.cond.Broadcast()
+	return ev
+}
+
+func (ev *simTimer) Stop() bool {
+	ev.s.mu.Lock()
+	defer ev.s.mu.Unlock()
+
+	if ev.index < 0 {
+		return false
+	}
+	heap.Remove(&ev.s.scheduled, ev.index)
+	ev.s.cond.Broadcast()
+	ev.index = -1
+	return true
+}
+
+func (ev *simTimer) Reset(d time.Duration) {
+	if ev.ch == nil {
+		panic("mclock: Reset() on timer created by AfterFunc")
+	}
+
+	ev.s.mu.Lock()
+	defer ev.s.mu.Unlock()
+	ev.at = ev.s.now.Add(d)
+	if ev.index < 0 {
+		heap.Push(&ev.s.scheduled, ev) // already expired
+	} else {
+		heap.Fix(&ev.s.scheduled, ev.index) // hasn't fired yet, reschedule
+	}
+	ev.s.cond.Broadcast()
+}
+
+func (ev *simTimer) C() <-chan AbsTime {
+	if ev.ch == nil {
+		panic("mclock: C() on timer created by AfterFunc")
+	}
+	return ev.ch
+}
+
+type simTimerHeap []*simTimer
+
+func (h *simTimerHeap) Len() int {
+	return len(*h)
+}
+
+func (h *simTimerHeap) Less(i, j int) bool {
+	return (*h)[i].at < (*h)[j].at
+}
+
+func (h *simTimerHeap) Swap(i, j int) {
+	(*h)[i], (*h)[j] = (*h)[j], (*h)[i]
+	(*h)[i].index = i
+	(*h)[j].index = j
+}
+
+func (h *simTimerHeap) Push(x interface{}) {
+	t := x.(*simTimer)
+	t.index = len(*h)
+	*h = append(*h, t)
+}
+
+func (h *simTimerHeap) Pop() interface{} {
+	end := len(*h) - 1
+	t := (*h)[end]
+	t.index = -1
+	(*h)[end] = nil
+	*h = (*h)[:end]
+	return t
+}

+ 162 - 0
common/mclock/simclock_test.go

@@ -0,0 +1,162 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package mclock
+
+import (
+	"testing"
+	"time"
+)
+
+var _ Clock = System{}
+var _ Clock = new(Simulated)
+
+func TestSimulatedAfter(t *testing.T) {
+	var (
+		timeout = 30 * time.Minute
+		offset  = 99 * time.Hour
+		adv     = 11 * time.Minute
+		c       Simulated
+	)
+	c.Run(offset)
+
+	end := c.Now().Add(timeout)
+	ch := c.After(timeout)
+	for c.Now() < end.Add(-adv) {
+		c.Run(adv)
+		select {
+		case <-ch:
+			t.Fatal("Timer fired early")
+		default:
+		}
+	}
+
+	c.Run(adv)
+	select {
+	case stamp := <-ch:
+		want := AbsTime(0).Add(offset).Add(timeout)
+		if stamp != want {
+			t.Errorf("Wrong time sent on timer channel: got %v, want %v", stamp, want)
+		}
+	default:
+		t.Fatal("Timer didn't fire")
+	}
+}
+
+func TestSimulatedAfterFunc(t *testing.T) {
+	var c Simulated
+
+	called1 := false
+	timer1 := c.AfterFunc(100*time.Millisecond, func() { called1 = true })
+	if c.ActiveTimers() != 1 {
+		t.Fatalf("%d active timers, want one", c.ActiveTimers())
+	}
+	if fired := timer1.Stop(); !fired {
+		t.Fatal("Stop returned false even though timer didn't fire")
+	}
+	if c.ActiveTimers() != 0 {
+		t.Fatalf("%d active timers, want zero", c.ActiveTimers())
+	}
+	if called1 {
+		t.Fatal("timer 1 called")
+	}
+	if fired := timer1.Stop(); fired {
+		t.Fatal("Stop returned true after timer was already stopped")
+	}
+
+	called2 := false
+	timer2 := c.AfterFunc(100*time.Millisecond, func() { called2 = true })
+	c.Run(50 * time.Millisecond)
+	if called2 {
+		t.Fatal("timer 2 called")
+	}
+	c.Run(51 * time.Millisecond)
+	if !called2 {
+		t.Fatal("timer 2 not called")
+	}
+	if fired := timer2.Stop(); fired {
+		t.Fatal("Stop returned true after timer has fired")
+	}
+}
+
+func TestSimulatedSleep(t *testing.T) {
+	var (
+		c       Simulated
+		timeout = 1 * time.Hour
+		done    = make(chan AbsTime, 1)
+	)
+	go func() {
+		c.Sleep(timeout)
+		done <- c.Now()
+	}()
+
+	c.WaitForTimers(1)
+	c.Run(2 * timeout)
+	select {
+	case stamp := <-done:
+		want := AbsTime(2 * timeout)
+		if stamp != want {
+			t.Errorf("Wrong time after sleep: got %v, want %v", stamp, want)
+		}
+	case <-time.After(5 * time.Second):
+		t.Fatal("Sleep didn't return in time")
+	}
+}
+
+func TestSimulatedTimerReset(t *testing.T) {
+	var (
+		c       Simulated
+		timeout = 1 * time.Hour
+	)
+	timer := c.NewTimer(timeout)
+	c.Run(2 * timeout)
+	select {
+	case ftime := <-timer.C():
+		if ftime != AbsTime(timeout) {
+			t.Fatalf("wrong time %v sent on timer channel, want %v", ftime, AbsTime(timeout))
+		}
+	default:
+		t.Fatal("timer didn't fire")
+	}
+
+	timer.Reset(timeout)
+	c.Run(2 * timeout)
+	select {
+	case ftime := <-timer.C():
+		if ftime != AbsTime(3*timeout) {
+			t.Fatalf("wrong time %v sent on timer channel, want %v", ftime, AbsTime(3*timeout))
+		}
+	default:
+		t.Fatal("timer didn't fire again")
+	}
+}
+
+func TestSimulatedTimerStop(t *testing.T) {
+	var (
+		c       Simulated
+		timeout = 1 * time.Hour
+	)
+	timer := c.NewTimer(timeout)
+	c.Run(2 * timeout)
+	if timer.Stop() {
+		t.Errorf("Stop returned true for fired timer")
+	}
+	select {
+	case <-timer.C():
+	default:
+		t.Fatal("timer didn't fire")
+	}
+}

+ 49 - 0
common/path.go

@@ -0,0 +1,49 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package common
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"runtime"
+)
+
+// MakeName creates a node name that follows the ethereum convention
+// for such names. It adds the operation system name and Go runtime version
+// the name.
+func MakeName(name, version string) string {
+	return fmt.Sprintf("%s/v%s/%s/%s", name, version, runtime.GOOS, runtime.Version())
+}
+
+// FileExist checks if a file exists at filePath.
+func FileExist(filePath string) bool {
+	_, err := os.Stat(filePath)
+	if err != nil && os.IsNotExist(err) {
+		return false
+	}
+
+	return true
+}
+
+// AbsolutePath returns datadir + filename, or filename if it is absolute.
+func AbsolutePath(datadir string, filename string) string {
+	if filepath.IsAbs(filename) {
+		return filename
+	}
+	return filepath.Join(datadir, filename)
+}

+ 196 - 0
common/prque/lazyqueue.go

@@ -0,0 +1,196 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package prque
+
+import (
+	"container/heap"
+	"time"
+
+	"github.com/ethereum/go-ethereum/common/mclock"
+)
+
+// LazyQueue is a priority queue data structure where priorities can change over
+// time and are only evaluated on demand.
+// Two callbacks are required:
+// - priority evaluates the actual priority of an item
+// - maxPriority gives an upper estimate for the priority in any moment between
+//   now and the given absolute time
+// If the upper estimate is exceeded then Update should be called for that item.
+// A global Refresh function should also be called periodically.
+type LazyQueue struct {
+	clock mclock.Clock
+	// Items are stored in one of two internal queues ordered by estimated max
+	// priority until the next and the next-after-next refresh. Update and Refresh
+	// always places items in queue[1].
+	queue                      [2]*sstack
+	popQueue                   *sstack
+	period                     time.Duration
+	maxUntil                   mclock.AbsTime
+	indexOffset                int
+	setIndex                   SetIndexCallback
+	priority                   PriorityCallback
+	maxPriority                MaxPriorityCallback
+	lastRefresh1, lastRefresh2 mclock.AbsTime
+}
+
+type (
+	PriorityCallback    func(data interface{}) int64                       // actual priority callback
+	MaxPriorityCallback func(data interface{}, until mclock.AbsTime) int64 // estimated maximum priority callback
+)
+
+// NewLazyQueue creates a new lazy queue
+func NewLazyQueue(setIndex SetIndexCallback, priority PriorityCallback, maxPriority MaxPriorityCallback, clock mclock.Clock, refreshPeriod time.Duration) *LazyQueue {
+	q := &LazyQueue{
+		popQueue:     newSstack(nil, false),
+		setIndex:     setIndex,
+		priority:     priority,
+		maxPriority:  maxPriority,
+		clock:        clock,
+		period:       refreshPeriod,
+		lastRefresh1: clock.Now(),
+		lastRefresh2: clock.Now(),
+	}
+	q.Reset()
+	q.refresh(clock.Now())
+	return q
+}
+
+// Reset clears the contents of the queue
+func (q *LazyQueue) Reset() {
+	q.queue[0] = newSstack(q.setIndex0, false)
+	q.queue[1] = newSstack(q.setIndex1, false)
+}
+
+// Refresh performs queue re-evaluation if necessary
+func (q *LazyQueue) Refresh() {
+	now := q.clock.Now()
+	for time.Duration(now-q.lastRefresh2) >= q.period*2 {
+		q.refresh(now)
+		q.lastRefresh2 = q.lastRefresh1
+		q.lastRefresh1 = now
+	}
+}
+
+// refresh re-evaluates items in the older queue and swaps the two queues
+func (q *LazyQueue) refresh(now mclock.AbsTime) {
+	q.maxUntil = now + mclock.AbsTime(q.period)
+	for q.queue[0].Len() != 0 {
+		q.Push(heap.Pop(q.queue[0]).(*item).value)
+	}
+	q.queue[0], q.queue[1] = q.queue[1], q.queue[0]
+	q.indexOffset = 1 - q.indexOffset
+	q.maxUntil += mclock.AbsTime(q.period)
+}
+
+// Push adds an item to the queue
+func (q *LazyQueue) Push(data interface{}) {
+	heap.Push(q.queue[1], &item{data, q.maxPriority(data, q.maxUntil)})
+}
+
+// Update updates the upper priority estimate for the item with the given queue index
+func (q *LazyQueue) Update(index int) {
+	q.Push(q.Remove(index))
+}
+
+// Pop removes and returns the item with the greatest actual priority
+func (q *LazyQueue) Pop() (interface{}, int64) {
+	var (
+		resData interface{}
+		resPri  int64
+	)
+	q.MultiPop(func(data interface{}, priority int64) bool {
+		resData = data
+		resPri = priority
+		return false
+	})
+	return resData, resPri
+}
+
+// peekIndex returns the index of the internal queue where the item with the
+// highest estimated priority is or -1 if both are empty
+func (q *LazyQueue) peekIndex() int {
+	if q.queue[0].Len() != 0 {
+		if q.queue[1].Len() != 0 && q.queue[1].blocks[0][0].priority > q.queue[0].blocks[0][0].priority {
+			return 1
+		}
+		return 0
+	}
+	if q.queue[1].Len() != 0 {
+		return 1
+	}
+	return -1
+}
+
+// MultiPop pops multiple items from the queue and is more efficient than calling
+// Pop multiple times. Popped items are passed to the callback. MultiPop returns
+// when the callback returns false or there are no more items to pop.
+func (q *LazyQueue) MultiPop(callback func(data interface{}, priority int64) bool) {
+	nextIndex := q.peekIndex()
+	for nextIndex != -1 {
+		data := heap.Pop(q.queue[nextIndex]).(*item).value
+		heap.Push(q.popQueue, &item{data, q.priority(data)})
+		nextIndex = q.peekIndex()
+		for q.popQueue.Len() != 0 && (nextIndex == -1 || q.queue[nextIndex].blocks[0][0].priority < q.popQueue.blocks[0][0].priority) {
+			i := heap.Pop(q.popQueue).(*item)
+			if !callback(i.value, i.priority) {
+				for q.popQueue.Len() != 0 {
+					q.Push(heap.Pop(q.popQueue).(*item).value)
+				}
+				return
+			}
+			nextIndex = q.peekIndex() // re-check because callback is allowed to push items back
+		}
+	}
+}
+
+// PopItem pops the item from the queue only, dropping the associated priority value.
+func (q *LazyQueue) PopItem() interface{} {
+	i, _ := q.Pop()
+	return i
+}
+
+// Remove removes removes the item with the given index.
+func (q *LazyQueue) Remove(index int) interface{} {
+	if index < 0 {
+		return nil
+	}
+	return heap.Remove(q.queue[index&1^q.indexOffset], index>>1).(*item).value
+}
+
+// Empty checks whether the priority queue is empty.
+func (q *LazyQueue) Empty() bool {
+	return q.queue[0].Len() == 0 && q.queue[1].Len() == 0
+}
+
+// Size returns the number of items in the priority queue.
+func (q *LazyQueue) Size() int {
+	return q.queue[0].Len() + q.queue[1].Len()
+}
+
+// setIndex0 translates internal queue item index to the virtual index space of LazyQueue
+func (q *LazyQueue) setIndex0(data interface{}, index int) {
+	if index == -1 {
+		q.setIndex(data, -1)
+	} else {
+		q.setIndex(data, index+index)
+	}
+}
+
+// setIndex1 translates internal queue item index to the virtual index space of LazyQueue
+func (q *LazyQueue) setIndex1(data interface{}, index int) {
+	q.setIndex(data, index+index+1)
+}

+ 124 - 0
common/prque/lazyqueue_test.go

@@ -0,0 +1,124 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package prque
+
+import (
+	"math/rand"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/ethereum/go-ethereum/common/mclock"
+)
+
+const (
+	testItems        = 1000
+	testPriorityStep = 100
+	testSteps        = 1000000
+	testStepPeriod   = time.Millisecond
+	testQueueRefresh = time.Second
+	testAvgRate      = float64(testPriorityStep) / float64(testItems) / float64(testStepPeriod)
+)
+
+type lazyItem struct {
+	p, maxp int64
+	last    mclock.AbsTime
+	index   int
+}
+
+func testPriority(a interface{}) int64 {
+	return a.(*lazyItem).p
+}
+
+func testMaxPriority(a interface{}, until mclock.AbsTime) int64 {
+	i := a.(*lazyItem)
+	dt := until - i.last
+	i.maxp = i.p + int64(float64(dt)*testAvgRate)
+	return i.maxp
+}
+
+func testSetIndex(a interface{}, i int) {
+	a.(*lazyItem).index = i
+}
+
+func TestLazyQueue(t *testing.T) {
+	rand.Seed(time.Now().UnixNano())
+	clock := &mclock.Simulated{}
+	q := NewLazyQueue(testSetIndex, testPriority, testMaxPriority, clock, testQueueRefresh)
+
+	var (
+		items  [testItems]lazyItem
+		maxPri int64
+	)
+
+	for i := range items[:] {
+		items[i].p = rand.Int63n(testPriorityStep * 10)
+		if items[i].p > maxPri {
+			maxPri = items[i].p
+		}
+		items[i].index = -1
+		q.Push(&items[i])
+	}
+
+	var (
+		lock   sync.Mutex
+		wg     sync.WaitGroup
+		stopCh = make(chan chan struct{})
+	)
+	defer wg.Wait()
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		for {
+			select {
+			case <-clock.After(testQueueRefresh):
+				lock.Lock()
+				q.Refresh()
+				lock.Unlock()
+			case <-stopCh:
+				return
+			}
+		}
+	}()
+
+	for c := 0; c < testSteps; c++ {
+		i := rand.Intn(testItems)
+		lock.Lock()
+		items[i].p += rand.Int63n(testPriorityStep*2-1) + 1
+		if items[i].p > maxPri {
+			maxPri = items[i].p
+		}
+		items[i].last = clock.Now()
+		if items[i].p > items[i].maxp {
+			q.Update(items[i].index)
+		}
+		if rand.Intn(100) == 0 {
+			p := q.PopItem().(*lazyItem)
+			if p.p != maxPri {
+				lock.Unlock()
+				close(stopCh)
+				t.Fatalf("incorrect item (best known priority %d, popped %d)", maxPri, p.p)
+			}
+			q.Push(p)
+		}
+		lock.Unlock()
+		clock.Run(testStepPeriod)
+		clock.WaitForTimers(1)
+	}
+
+	close(stopCh)
+}

+ 83 - 0
common/prque/prque.go

@@ -0,0 +1,83 @@
+// CookieJar - A contestant's algorithm toolbox
+// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
+//
+// CookieJar is dual licensed: use of this source code is governed by a BSD
+// license that can be found in the LICENSE file. Alternatively, the CookieJar
+// toolbox may be used in accordance with the terms and conditions contained
+// in a signed written agreement between you and the author(s).
+
+// This is a duplicated and slightly modified version of "gopkg.in/karalabe/cookiejar.v2/collections/prque".
+
+// Package prque implements a priority queue data structure supporting arbitrary
+// value types and int64 priorities.
+//
+// If you would like to use a min-priority queue, simply negate the priorities.
+//
+// Internally the queue is based on the standard heap package working on a
+// sortable version of the block based stack.
+package prque
+
+import (
+	"container/heap"
+)
+
+// Priority queue data structure.
+type Prque struct {
+	cont *sstack
+}
+
+// New creates a new priority queue.
+func New(setIndex SetIndexCallback) *Prque {
+	return &Prque{newSstack(setIndex, false)}
+}
+
+// NewWrapAround creates a new priority queue with wrap-around priority handling.
+func NewWrapAround(setIndex SetIndexCallback) *Prque {
+	return &Prque{newSstack(setIndex, true)}
+}
+
+// Pushes a value with a given priority into the queue, expanding if necessary.
+func (p *Prque) Push(data interface{}, priority int64) {
+	heap.Push(p.cont, &item{data, priority})
+}
+
+// Peek returns the value with the greates priority but does not pop it off.
+func (p *Prque) Peek() (interface{}, int64) {
+	item := p.cont.blocks[0][0]
+	return item.value, item.priority
+}
+
+// Pops the value with the greates priority off the stack and returns it.
+// Currently no shrinking is done.
+func (p *Prque) Pop() (interface{}, int64) {
+	item := heap.Pop(p.cont).(*item)
+	return item.value, item.priority
+}
+
+// Pops only the item from the queue, dropping the associated priority value.
+func (p *Prque) PopItem() interface{} {
+	return heap.Pop(p.cont).(*item).value
+}
+
+// Remove removes the element with the given index.
+func (p *Prque) Remove(i int) interface{} {
+	if i < 0 {
+		return nil
+	}
+	return heap.Remove(p.cont, i)
+}
+
+// Checks whether the priority queue is empty.
+func (p *Prque) Empty() bool {
+	return p.cont.Len() == 0
+}
+
+// Returns the number of element in the priority queue.
+func (p *Prque) Size() int {
+	return p.cont.Len()
+}
+
+// Clears the contents of the priority queue.
+func (p *Prque) Reset() {
+	*p = *New(p.cont.setIndex)
+}

+ 130 - 0
common/prque/prque_test.go

@@ -0,0 +1,130 @@
+// CookieJar - A contestant's algorithm toolbox
+// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
+//
+// CookieJar is dual licensed: use of this source code is governed by a BSD
+// license that can be found in the LICENSE file. Alternatively, the CookieJar
+// toolbox may be used in accordance with the terms and conditions contained
+// in a signed written agreement between you and the author(s).
+
+package prque
+
+import (
+	"math/rand"
+	"testing"
+)
+
+func TestPrque(t *testing.T) {
+	// Generate a batch of random data and a specific priority order
+	size := 16 * blockSize
+	prio := rand.Perm(size)
+	data := make([]int, size)
+	for i := 0; i < size; i++ {
+		data[i] = rand.Int()
+	}
+	queue := New(nil)
+	for rep := 0; rep < 2; rep++ {
+		// Fill a priority queue with the above data
+		for i := 0; i < size; i++ {
+			queue.Push(data[i], int64(prio[i]))
+			if queue.Size() != i+1 {
+				t.Errorf("queue size mismatch: have %v, want %v.", queue.Size(), i+1)
+			}
+		}
+		// Create a map the values to the priorities for easier verification
+		dict := make(map[int64]int)
+		for i := 0; i < size; i++ {
+			dict[int64(prio[i])] = data[i]
+		}
+		// Pop out the elements in priority order and verify them
+		prevPrio := int64(size + 1)
+		for !queue.Empty() {
+			val, prio := queue.Pop()
+			if prio > prevPrio {
+				t.Errorf("invalid priority order: %v after %v.", prio, prevPrio)
+			}
+			prevPrio = prio
+			if val != dict[prio] {
+				t.Errorf("push/pop mismatch: have %v, want %v.", val, dict[prio])
+			}
+			delete(dict, prio)
+		}
+	}
+}
+
+func TestReset(t *testing.T) {
+	// Generate a batch of random data and a specific priority order
+	size := 16 * blockSize
+	prio := rand.Perm(size)
+	data := make([]int, size)
+	for i := 0; i < size; i++ {
+		data[i] = rand.Int()
+	}
+	queue := New(nil)
+	for rep := 0; rep < 2; rep++ {
+		// Fill a priority queue with the above data
+		for i := 0; i < size; i++ {
+			queue.Push(data[i], int64(prio[i]))
+			if queue.Size() != i+1 {
+				t.Errorf("queue size mismatch: have %v, want %v.", queue.Size(), i+1)
+			}
+		}
+		// Create a map the values to the priorities for easier verification
+		dict := make(map[int64]int)
+		for i := 0; i < size; i++ {
+			dict[int64(prio[i])] = data[i]
+		}
+		// Pop out half the elements in priority order and verify them
+		prevPrio := int64(size + 1)
+		for i := 0; i < size/2; i++ {
+			val, prio := queue.Pop()
+			if prio > prevPrio {
+				t.Errorf("invalid priority order: %v after %v.", prio, prevPrio)
+			}
+			prevPrio = prio
+			if val != dict[prio] {
+				t.Errorf("push/pop mismatch: have %v, want %v.", val, dict[prio])
+			}
+			delete(dict, prio)
+		}
+		// Reset and ensure it's empty
+		queue.Reset()
+		if !queue.Empty() {
+			t.Errorf("priority queue not empty after reset: %v", queue)
+		}
+	}
+}
+
+func BenchmarkPush(b *testing.B) {
+	// Create some initial data
+	data := make([]int, b.N)
+	prio := make([]int64, b.N)
+	for i := 0; i < len(data); i++ {
+		data[i] = rand.Int()
+		prio[i] = rand.Int63()
+	}
+	// Execute the benchmark
+	b.ResetTimer()
+	queue := New(nil)
+	for i := 0; i < len(data); i++ {
+		queue.Push(data[i], prio[i])
+	}
+}
+
+func BenchmarkPop(b *testing.B) {
+	// Create some initial data
+	data := make([]int, b.N)
+	prio := make([]int64, b.N)
+	for i := 0; i < len(data); i++ {
+		data[i] = rand.Int()
+		prio[i] = rand.Int63()
+	}
+	queue := New(nil)
+	for i := 0; i < len(data); i++ {
+		queue.Push(data[i], prio[i])
+	}
+	// Execute the benchmark
+	b.ResetTimer()
+	for !queue.Empty() {
+		queue.Pop()
+	}
+}

+ 120 - 0
common/prque/sstack.go

@@ -0,0 +1,120 @@
+// CookieJar - A contestant's algorithm toolbox
+// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
+//
+// CookieJar is dual licensed: use of this source code is governed by a BSD
+// license that can be found in the LICENSE file. Alternatively, the CookieJar
+// toolbox may be used in accordance with the terms and conditions contained
+// in a signed written agreement between you and the author(s).
+
+// This is a duplicated and slightly modified version of "gopkg.in/karalabe/cookiejar.v2/collections/prque".
+
+package prque
+
+// The size of a block of data
+const blockSize = 4096
+
+// A prioritized item in the sorted stack.
+//
+// Note: priorities can "wrap around" the int64 range, a comes before b if (a.priority - b.priority) > 0.
+// The difference between the lowest and highest priorities in the queue at any point should be less than 2^63.
+type item struct {
+	value    interface{}
+	priority int64
+}
+
+// SetIndexCallback is called when the element is moved to a new index.
+// Providing SetIndexCallback is optional, it is needed only if the application needs
+// to delete elements other than the top one.
+type SetIndexCallback func(data interface{}, index int)
+
+// Internal sortable stack data structure. Implements the Push and Pop ops for
+// the stack (heap) functionality and the Len, Less and Swap methods for the
+// sortability requirements of the heaps.
+type sstack struct {
+	setIndex   SetIndexCallback
+	size       int
+	capacity   int
+	offset     int
+	wrapAround bool
+
+	blocks [][]*item
+	active []*item
+}
+
+// Creates a new, empty stack.
+func newSstack(setIndex SetIndexCallback, wrapAround bool) *sstack {
+	result := new(sstack)
+	result.setIndex = setIndex
+	result.active = make([]*item, blockSize)
+	result.blocks = [][]*item{result.active}
+	result.capacity = blockSize
+	result.wrapAround = wrapAround
+	return result
+}
+
+// Pushes a value onto the stack, expanding it if necessary. Required by
+// heap.Interface.
+func (s *sstack) Push(data interface{}) {
+	if s.size == s.capacity {
+		s.active = make([]*item, blockSize)
+		s.blocks = append(s.blocks, s.active)
+		s.capacity += blockSize
+		s.offset = 0
+	} else if s.offset == blockSize {
+		s.active = s.blocks[s.size/blockSize]
+		s.offset = 0
+	}
+	if s.setIndex != nil {
+		s.setIndex(data.(*item).value, s.size)
+	}
+	s.active[s.offset] = data.(*item)
+	s.offset++
+	s.size++
+}
+
+// Pops a value off the stack and returns it. Currently no shrinking is done.
+// Required by heap.Interface.
+func (s *sstack) Pop() (res interface{}) {
+	s.size--
+	s.offset--
+	if s.offset < 0 {
+		s.offset = blockSize - 1
+		s.active = s.blocks[s.size/blockSize]
+	}
+	res, s.active[s.offset] = s.active[s.offset], nil
+	if s.setIndex != nil {
+		s.setIndex(res.(*item).value, -1)
+	}
+	return
+}
+
+// Returns the length of the stack. Required by sort.Interface.
+func (s *sstack) Len() int {
+	return s.size
+}
+
+// Compares the priority of two elements of the stack (higher is first).
+// Required by sort.Interface.
+func (s *sstack) Less(i, j int) bool {
+	a, b := s.blocks[i/blockSize][i%blockSize].priority, s.blocks[j/blockSize][j%blockSize].priority
+	if s.wrapAround {
+		return a-b > 0
+	}
+	return a > b
+}
+
+// Swaps two elements in the stack. Required by sort.Interface.
+func (s *sstack) Swap(i, j int) {
+	ib, io, jb, jo := i/blockSize, i%blockSize, j/blockSize, j%blockSize
+	a, b := s.blocks[jb][jo], s.blocks[ib][io]
+	if s.setIndex != nil {
+		s.setIndex(a.value, i)
+		s.setIndex(b.value, j)
+	}
+	s.blocks[ib][io], s.blocks[jb][jo] = a, b
+}
+
+// Resets the stack, effectively clearing its contents.
+func (s *sstack) Reset() {
+	*s = *newSstack(s.setIndex, false)
+}

+ 100 - 0
common/prque/sstack_test.go

@@ -0,0 +1,100 @@
+// CookieJar - A contestant's algorithm toolbox
+// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
+//
+// CookieJar is dual licensed: use of this source code is governed by a BSD
+// license that can be found in the LICENSE file. Alternatively, the CookieJar
+// toolbox may be used in accordance with the terms and conditions contained
+// in a signed written agreement between you and the author(s).
+
+package prque
+
+import (
+	"math/rand"
+	"sort"
+	"testing"
+)
+
+func TestSstack(t *testing.T) {
+	// Create some initial data
+	size := 16 * blockSize
+	data := make([]*item, size)
+	for i := 0; i < size; i++ {
+		data[i] = &item{rand.Int(), rand.Int63()}
+	}
+	stack := newSstack(nil, false)
+	for rep := 0; rep < 2; rep++ {
+		// Push all the data into the stack, pop out every second
+		secs := []*item{}
+		for i := 0; i < size; i++ {
+			stack.Push(data[i])
+			if i%2 == 0 {
+				secs = append(secs, stack.Pop().(*item))
+			}
+		}
+		rest := []*item{}
+		for stack.Len() > 0 {
+			rest = append(rest, stack.Pop().(*item))
+		}
+		// Make sure the contents of the resulting slices are ok
+		for i := 0; i < size; i++ {
+			if i%2 == 0 && data[i] != secs[i/2] {
+				t.Errorf("push/pop mismatch: have %v, want %v.", secs[i/2], data[i])
+			}
+			if i%2 == 1 && data[i] != rest[len(rest)-i/2-1] {
+				t.Errorf("push/pop mismatch: have %v, want %v.", rest[len(rest)-i/2-1], data[i])
+			}
+		}
+	}
+}
+
+func TestSstackSort(t *testing.T) {
+	// Create some initial data
+	size := 16 * blockSize
+	data := make([]*item, size)
+	for i := 0; i < size; i++ {
+		data[i] = &item{rand.Int(), int64(i)}
+	}
+	// Push all the data into the stack
+	stack := newSstack(nil, false)
+	for _, val := range data {
+		stack.Push(val)
+	}
+	// Sort and pop the stack contents (should reverse the order)
+	sort.Sort(stack)
+	for _, val := range data {
+		out := stack.Pop()
+		if out != val {
+			t.Errorf("push/pop mismatch after sort: have %v, want %v.", out, val)
+		}
+	}
+}
+
+func TestSstackReset(t *testing.T) {
+	// Create some initial data
+	size := 16 * blockSize
+	data := make([]*item, size)
+	for i := 0; i < size; i++ {
+		data[i] = &item{rand.Int(), rand.Int63()}
+	}
+	stack := newSstack(nil, false)
+	for rep := 0; rep < 2; rep++ {
+		// Push all the data into the stack, pop out every second
+		secs := []*item{}
+		for i := 0; i < size; i++ {
+			stack.Push(data[i])
+			if i%2 == 0 {
+				secs = append(secs, stack.Pop().(*item))
+			}
+		}
+		// Reset and verify both pulled and stack contents
+		stack.Reset()
+		if stack.Len() != 0 {
+			t.Errorf("stack not empty after reset: %v", stack)
+		}
+		for i := 0; i < size; i++ {
+			if i%2 == 0 && data[i] != secs[i/2] {
+				t.Errorf("push/pop mismatch: have %v, want %v.", secs[i/2], data[i])
+			}
+		}
+	}
+}

+ 56 - 0
common/size.go

@@ -0,0 +1,56 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package common
+
+import (
+	"fmt"
+)
+
+// StorageSize is a wrapper around a float value that supports user friendly
+// formatting.
+type StorageSize float64
+
+// String implements the stringer interface.
+func (s StorageSize) String() string {
+	if s > 1099511627776 {
+		return fmt.Sprintf("%.2f TiB", s/1099511627776)
+	} else if s > 1073741824 {
+		return fmt.Sprintf("%.2f GiB", s/1073741824)
+	} else if s > 1048576 {
+		return fmt.Sprintf("%.2f MiB", s/1048576)
+	} else if s > 1024 {
+		return fmt.Sprintf("%.2f KiB", s/1024)
+	} else {
+		return fmt.Sprintf("%.2f B", s)
+	}
+}
+
+// TerminalString implements log.TerminalStringer, formatting a string for console
+// output during logging.
+func (s StorageSize) TerminalString() string {
+	if s > 1099511627776 {
+		return fmt.Sprintf("%.2fTiB", s/1099511627776)
+	} else if s > 1073741824 {
+		return fmt.Sprintf("%.2fGiB", s/1073741824)
+	} else if s > 1048576 {
+		return fmt.Sprintf("%.2fMiB", s/1048576)
+	} else if s > 1024 {
+		return fmt.Sprintf("%.2fKiB", s/1024)
+	} else {
+		return fmt.Sprintf("%.2fB", s)
+	}
+}

+ 38 - 0
common/size_test.go

@@ -0,0 +1,38 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package common
+
+import (
+	"testing"
+)
+
+func TestStorageSizeString(t *testing.T) {
+	tests := []struct {
+		size StorageSize
+		str  string
+	}{
+		{2381273, "2.27 MiB"},
+		{2192, "2.14 KiB"},
+		{12, "12.00 B"},
+	}
+
+	for _, test := range tests {
+		if test.size.String() != test.str {
+			t.Errorf("%f: got %q, want %q", float64(test.size), test.size.String(), test.str)
+		}
+	}
+}

+ 53 - 0
common/test_utils.go

@@ -0,0 +1,53 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package common
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+)
+
+// LoadJSON reads the given file and unmarshals its content.
+func LoadJSON(file string, val interface{}) error {
+	content, err := ioutil.ReadFile(file)
+	if err != nil {
+		return err
+	}
+	if err := json.Unmarshal(content, val); err != nil {
+		if syntaxerr, ok := err.(*json.SyntaxError); ok {
+			line := findLine(content, syntaxerr.Offset)
+			return fmt.Errorf("JSON syntax error at %v:%v: %v", file, line, err)
+		}
+		return fmt.Errorf("JSON unmarshal error in %v: %v", file, err)
+	}
+	return nil
+}
+
+// findLine returns the line number for the given offset into data.
+func findLine(data []byte, offset int64) (line int) {
+	line = 1
+	for i, r := range string(data) {
+		if int64(i) >= offset {
+			return
+		}
+		if r == '\n' {
+			line++
+		}
+	}
+	return
+}

+ 428 - 0
common/types.go

@@ -0,0 +1,428 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package common
+
+import (
+	"bytes"
+	"database/sql/driver"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"math/big"
+	"math/rand"
+	"reflect"
+	"strings"
+
+	"github.com/ethereum/go-ethereum/common/hexutil"
+	"golang.org/x/crypto/sha3"
+)
+
+// Lengths of hashes and addresses in bytes.
+const (
+	// HashLength is the expected length of the hash
+	HashLength = 32
+	// AddressLength is the expected length of the address
+	AddressLength = 20
+)
+
+var (
+	hashT    = reflect.TypeOf(Hash{})
+	addressT = reflect.TypeOf(Address{})
+)
+
+// Hash represents the 32 byte Keccak256 hash of arbitrary data.
+type Hash [HashLength]byte
+
+// BytesToHash sets b to hash.
+// If b is larger than len(h), b will be cropped from the left.
+func BytesToHash(b []byte) Hash {
+	var h Hash
+	h.SetBytes(b)
+	return h
+}
+
+// BigToHash sets byte representation of b to hash.
+// If b is larger than len(h), b will be cropped from the left.
+func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
+
+// HexToHash sets byte representation of s to hash.
+// If b is larger than len(h), b will be cropped from the left.
+func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
+
+// Bytes gets the byte representation of the underlying hash.
+func (h Hash) Bytes() []byte { return h[:] }
+
+// Big converts a hash to a big integer.
+func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
+
+// Hex converts a hash to a hex string.
+func (h Hash) Hex() string { return hexutil.Encode(h[:]) }
+
+// TerminalString implements log.TerminalStringer, formatting a string for console
+// output during logging.
+func (h Hash) TerminalString() string {
+	return fmt.Sprintf("%x..%x", h[:3], h[29:])
+}
+
+// String implements the stringer interface and is used also by the logger when
+// doing full logging into a file.
+func (h Hash) String() string {
+	return h.Hex()
+}
+
+// Format implements fmt.Formatter.
+// Hash supports the %v, %s, %v, %x, %X and %d format verbs.
+func (h Hash) Format(s fmt.State, c rune) {
+	hexb := make([]byte, 2+len(h)*2)
+	copy(hexb, "0x")
+	hex.Encode(hexb[2:], h[:])
+
+	switch c {
+	case 'x', 'X':
+		if !s.Flag('#') {
+			hexb = hexb[2:]
+		}
+		if c == 'X' {
+			hexb = bytes.ToUpper(hexb)
+		}
+		fallthrough
+	case 'v', 's':
+		s.Write(hexb)
+	case 'q':
+		q := []byte{'"'}
+		s.Write(q)
+		s.Write(hexb)
+		s.Write(q)
+	case 'd':
+		fmt.Fprint(s, ([len(h)]byte)(h))
+	default:
+		fmt.Fprintf(s, "%%!%c(hash=%x)", c, h)
+	}
+}
+
+// UnmarshalText parses a hash in hex syntax.
+func (h *Hash) UnmarshalText(input []byte) error {
+	return hexutil.UnmarshalFixedText("Hash", input, h[:])
+}
+
+// UnmarshalJSON parses a hash in hex syntax.
+func (h *Hash) UnmarshalJSON(input []byte) error {
+	return hexutil.UnmarshalFixedJSON(hashT, input, h[:])
+}
+
+// MarshalText returns the hex representation of h.
+func (h Hash) MarshalText() ([]byte, error) {
+	return hexutil.Bytes(h[:]).MarshalText()
+}
+
+// SetBytes sets the hash to the value of b.
+// If b is larger than len(h), b will be cropped from the left.
+func (h *Hash) SetBytes(b []byte) {
+	if len(b) > len(h) {
+		b = b[len(b)-HashLength:]
+	}
+
+	copy(h[HashLength-len(b):], b)
+}
+
+// Generate implements testing/quick.Generator.
+func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
+	m := rand.Intn(len(h))
+	for i := len(h) - 1; i > m; i-- {
+		h[i] = byte(rand.Uint32())
+	}
+	return reflect.ValueOf(h)
+}
+
+// Scan implements Scanner for database/sql.
+func (h *Hash) Scan(src interface{}) error {
+	srcB, ok := src.([]byte)
+	if !ok {
+		return fmt.Errorf("can't scan %T into Hash", src)
+	}
+	if len(srcB) != HashLength {
+		return fmt.Errorf("can't scan []byte of len %d into Hash, want %d", len(srcB), HashLength)
+	}
+	copy(h[:], srcB)
+	return nil
+}
+
+// Value implements valuer for database/sql.
+func (h Hash) Value() (driver.Value, error) {
+	return h[:], nil
+}
+
+// ImplementsGraphQLType returns true if Hash implements the specified GraphQL type.
+func (Hash) ImplementsGraphQLType(name string) bool { return name == "Bytes32" }
+
+// UnmarshalGraphQL unmarshals the provided GraphQL query data.
+func (h *Hash) UnmarshalGraphQL(input interface{}) error {
+	var err error
+	switch input := input.(type) {
+	case string:
+		err = h.UnmarshalText([]byte(input))
+	default:
+		err = fmt.Errorf("unexpected type %T for Hash", input)
+	}
+	return err
+}
+
+// UnprefixedHash allows marshaling a Hash without 0x prefix.
+type UnprefixedHash Hash
+
+// UnmarshalText decodes the hash from hex. The 0x prefix is optional.
+func (h *UnprefixedHash) UnmarshalText(input []byte) error {
+	return hexutil.UnmarshalFixedUnprefixedText("UnprefixedHash", input, h[:])
+}
+
+// MarshalText encodes the hash as hex.
+func (h UnprefixedHash) MarshalText() ([]byte, error) {
+	return []byte(hex.EncodeToString(h[:])), nil
+}
+
+/////////// Address
+
+// Address represents the 20 byte address of an Ethereum account.
+type Address [AddressLength]byte
+
+// BytesToAddress returns Address with value b.
+// If b is larger than len(h), b will be cropped from the left.
+func BytesToAddress(b []byte) Address {
+	var a Address
+	a.SetBytes(b)
+	return a
+}
+
+// BigToAddress returns Address with byte values of b.
+// If b is larger than len(h), b will be cropped from the left.
+func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
+
+// HexToAddress returns Address with byte values of s.
+// If s is larger than len(h), s will be cropped from the left.
+func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) }
+
+// IsHexAddress verifies whether a string can represent a valid hex-encoded
+// Ethereum address or not.
+func IsHexAddress(s string) bool {
+	if has0xPrefix(s) {
+		s = s[2:]
+	}
+	return len(s) == 2*AddressLength && isHex(s)
+}
+
+// Bytes gets the string representation of the underlying address.
+func (a Address) Bytes() []byte { return a[:] }
+
+// Hash converts an address to a hash by left-padding it with zeros.
+func (a Address) Hash() Hash { return BytesToHash(a[:]) }
+
+// Hex returns an EIP55-compliant hex string representation of the address.
+func (a Address) Hex() string {
+	return string(a.checksumHex())
+}
+
+// String implements fmt.Stringer.
+func (a Address) String() string {
+	return a.Hex()
+}
+
+func (a *Address) checksumHex() []byte {
+	buf := a.hex()
+
+	// compute checksum
+	sha := sha3.NewLegacyKeccak256()
+	sha.Write(buf[2:])
+	hash := sha.Sum(nil)
+	for i := 2; i < len(buf); i++ {
+		hashByte := hash[(i-2)/2]
+		if i%2 == 0 {
+			hashByte = hashByte >> 4
+		} else {
+			hashByte &= 0xf
+		}
+		if buf[i] > '9' && hashByte > 7 {
+			buf[i] -= 32
+		}
+	}
+	return buf[:]
+}
+
+func (a Address) hex() []byte {
+	var buf [len(a)*2 + 2]byte
+	copy(buf[:2], "0x")
+	hex.Encode(buf[2:], a[:])
+	return buf[:]
+}
+
+// Format implements fmt.Formatter.
+// Address supports the %v, %s, %v, %x, %X and %d format verbs.
+func (a Address) Format(s fmt.State, c rune) {
+	switch c {
+	case 'v', 's':
+		s.Write(a.checksumHex())
+	case 'q':
+		q := []byte{'"'}
+		s.Write(q)
+		s.Write(a.checksumHex())
+		s.Write(q)
+	case 'x', 'X':
+		// %x disables the checksum.
+		hex := a.hex()
+		if !s.Flag('#') {
+			hex = hex[2:]
+		}
+		if c == 'X' {
+			hex = bytes.ToUpper(hex)
+		}
+		s.Write(hex)
+	case 'd':
+		fmt.Fprint(s, ([len(a)]byte)(a))
+	default:
+		fmt.Fprintf(s, "%%!%c(address=%x)", c, a)
+	}
+}
+
+// SetBytes sets the address to the value of b.
+// If b is larger than len(a), b will be cropped from the left.
+func (a *Address) SetBytes(b []byte) {
+	if len(b) > len(a) {
+		b = b[len(b)-AddressLength:]
+	}
+	copy(a[AddressLength-len(b):], b)
+}
+
+// MarshalText returns the hex representation of a.
+func (a Address) MarshalText() ([]byte, error) {
+	return hexutil.Bytes(a[:]).MarshalText()
+}
+
+// UnmarshalText parses a hash in hex syntax.
+func (a *Address) UnmarshalText(input []byte) error {
+	return hexutil.UnmarshalFixedText("Address", input, a[:])
+}
+
+// UnmarshalJSON parses a hash in hex syntax.
+func (a *Address) UnmarshalJSON(input []byte) error {
+	return hexutil.UnmarshalFixedJSON(addressT, input, a[:])
+}
+
+// Scan implements Scanner for database/sql.
+func (a *Address) Scan(src interface{}) error {
+	srcB, ok := src.([]byte)
+	if !ok {
+		return fmt.Errorf("can't scan %T into Address", src)
+	}
+	if len(srcB) != AddressLength {
+		return fmt.Errorf("can't scan []byte of len %d into Address, want %d", len(srcB), AddressLength)
+	}
+	copy(a[:], srcB)
+	return nil
+}
+
+// Value implements valuer for database/sql.
+func (a Address) Value() (driver.Value, error) {
+	return a[:], nil
+}
+
+// ImplementsGraphQLType returns true if Hash implements the specified GraphQL type.
+func (a Address) ImplementsGraphQLType(name string) bool { return name == "Address" }
+
+// UnmarshalGraphQL unmarshals the provided GraphQL query data.
+func (a *Address) UnmarshalGraphQL(input interface{}) error {
+	var err error
+	switch input := input.(type) {
+	case string:
+		err = a.UnmarshalText([]byte(input))
+	default:
+		err = fmt.Errorf("unexpected type %T for Address", input)
+	}
+	return err
+}
+
+// UnprefixedAddress allows marshaling an Address without 0x prefix.
+type UnprefixedAddress Address
+
+// UnmarshalText decodes the address from hex. The 0x prefix is optional.
+func (a *UnprefixedAddress) UnmarshalText(input []byte) error {
+	return hexutil.UnmarshalFixedUnprefixedText("UnprefixedAddress", input, a[:])
+}
+
+// MarshalText encodes the address as hex.
+func (a UnprefixedAddress) MarshalText() ([]byte, error) {
+	return []byte(hex.EncodeToString(a[:])), nil
+}
+
+// MixedcaseAddress retains the original string, which may or may not be
+// correctly checksummed
+type MixedcaseAddress struct {
+	addr     Address
+	original string
+}
+
+// NewMixedcaseAddress constructor (mainly for testing)
+func NewMixedcaseAddress(addr Address) MixedcaseAddress {
+	return MixedcaseAddress{addr: addr, original: addr.Hex()}
+}
+
+// NewMixedcaseAddressFromString is mainly meant for unit-testing
+func NewMixedcaseAddressFromString(hexaddr string) (*MixedcaseAddress, error) {
+	if !IsHexAddress(hexaddr) {
+		return nil, errors.New("invalid address")
+	}
+	a := FromHex(hexaddr)
+	return &MixedcaseAddress{addr: BytesToAddress(a), original: hexaddr}, nil
+}
+
+// UnmarshalJSON parses MixedcaseAddress
+func (ma *MixedcaseAddress) UnmarshalJSON(input []byte) error {
+	if err := hexutil.UnmarshalFixedJSON(addressT, input, ma.addr[:]); err != nil {
+		return err
+	}
+	return json.Unmarshal(input, &ma.original)
+}
+
+// MarshalJSON marshals the original value
+func (ma *MixedcaseAddress) MarshalJSON() ([]byte, error) {
+	if strings.HasPrefix(ma.original, "0x") || strings.HasPrefix(ma.original, "0X") {
+		return json.Marshal(fmt.Sprintf("0x%s", ma.original[2:]))
+	}
+	return json.Marshal(fmt.Sprintf("0x%s", ma.original))
+}
+
+// Address returns the address
+func (ma *MixedcaseAddress) Address() Address {
+	return ma.addr
+}
+
+// String implements fmt.Stringer
+func (ma *MixedcaseAddress) String() string {
+	if ma.ValidChecksum() {
+		return fmt.Sprintf("%s [chksum ok]", ma.original)
+	}
+	return fmt.Sprintf("%s [chksum INVALID]", ma.original)
+}
+
+// ValidChecksum returns true if the address has valid checksum
+func (ma *MixedcaseAddress) ValidChecksum() bool {
+	return ma.original == ma.addr.Hex()
+}
+
+// Original returns the mixed-case input string
+func (ma *MixedcaseAddress) Original() string {
+	return ma.original
+}

+ 539 - 0
common/types_test.go

@@ -0,0 +1,539 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package common
+
+import (
+	"bytes"
+	"database/sql/driver"
+	"encoding/json"
+	"fmt"
+	"math/big"
+	"reflect"
+	"strings"
+	"testing"
+)
+
+func TestBytesConversion(t *testing.T) {
+	bytes := []byte{5}
+	hash := BytesToHash(bytes)
+
+	var exp Hash
+	exp[31] = 5
+
+	if hash != exp {
+		t.Errorf("expected %x got %x", exp, hash)
+	}
+}
+
+func TestIsHexAddress(t *testing.T) {
+	tests := []struct {
+		str string
+		exp bool
+	}{
+		{"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", true},
+		{"5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", true},
+		{"0X5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", true},
+		{"0XAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", true},
+		{"0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", true},
+		{"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed1", false},
+		{"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beae", false},
+		{"5aaeb6053f3e94c9b9a09f33669435e7ef1beaed11", false},
+		{"0xxaaeb6053f3e94c9b9a09f33669435e7ef1beaed", false},
+	}
+
+	for _, test := range tests {
+		if result := IsHexAddress(test.str); result != test.exp {
+			t.Errorf("IsHexAddress(%s) == %v; expected %v",
+				test.str, result, test.exp)
+		}
+	}
+}
+
+func TestHashJsonValidation(t *testing.T) {
+	var tests = []struct {
+		Prefix string
+		Size   int
+		Error  string
+	}{
+		{"", 62, "json: cannot unmarshal hex string without 0x prefix into Go value of type common.Hash"},
+		{"0x", 66, "hex string has length 66, want 64 for common.Hash"},
+		{"0x", 63, "json: cannot unmarshal hex string of odd length into Go value of type common.Hash"},
+		{"0x", 0, "hex string has length 0, want 64 for common.Hash"},
+		{"0x", 64, ""},
+		{"0X", 64, ""},
+	}
+	for _, test := range tests {
+		input := `"` + test.Prefix + strings.Repeat("0", test.Size) + `"`
+		var v Hash
+		err := json.Unmarshal([]byte(input), &v)
+		if err == nil {
+			if test.Error != "" {
+				t.Errorf("%s: error mismatch: have nil, want %q", input, test.Error)
+			}
+		} else {
+			if err.Error() != test.Error {
+				t.Errorf("%s: error mismatch: have %q, want %q", input, err, test.Error)
+			}
+		}
+	}
+}
+
+func TestAddressUnmarshalJSON(t *testing.T) {
+	var tests = []struct {
+		Input     string
+		ShouldErr bool
+		Output    *big.Int
+	}{
+		{"", true, nil},
+		{`""`, true, nil},
+		{`"0x"`, true, nil},
+		{`"0x00"`, true, nil},
+		{`"0xG000000000000000000000000000000000000000"`, true, nil},
+		{`"0x0000000000000000000000000000000000000000"`, false, big.NewInt(0)},
+		{`"0x0000000000000000000000000000000000000010"`, false, big.NewInt(16)},
+	}
+	for i, test := range tests {
+		var v Address
+		err := json.Unmarshal([]byte(test.Input), &v)
+		if err != nil && !test.ShouldErr {
+			t.Errorf("test #%d: unexpected error: %v", i, err)
+		}
+		if err == nil {
+			if test.ShouldErr {
+				t.Errorf("test #%d: expected error, got none", i)
+			}
+			if got := new(big.Int).SetBytes(v.Bytes()); got.Cmp(test.Output) != 0 {
+				t.Errorf("test #%d: address mismatch: have %v, want %v", i, got, test.Output)
+			}
+		}
+	}
+}
+
+func TestAddressHexChecksum(t *testing.T) {
+	var tests = []struct {
+		Input  string
+		Output string
+	}{
+		// Test cases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md#specification
+		{"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"},
+		{"0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359", "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"},
+		{"0xdbf03b407c01e7cd3cbea99509d93f8dddc8c6fb", "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"},
+		{"0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb", "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"},
+		// Ensure that non-standard length input values are handled correctly
+		{"0xa", "0x000000000000000000000000000000000000000A"},
+		{"0x0a", "0x000000000000000000000000000000000000000A"},
+		{"0x00a", "0x000000000000000000000000000000000000000A"},
+		{"0x000000000000000000000000000000000000000a", "0x000000000000000000000000000000000000000A"},
+	}
+	for i, test := range tests {
+		output := HexToAddress(test.Input).Hex()
+		if output != test.Output {
+			t.Errorf("test #%d: failed to match when it should (%s != %s)", i, output, test.Output)
+		}
+	}
+}
+
+func BenchmarkAddressHex(b *testing.B) {
+	testAddr := HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed")
+	for n := 0; n < b.N; n++ {
+		testAddr.Hex()
+	}
+}
+
+func TestMixedcaseAccount_Address(t *testing.T) {
+
+	// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md
+	// Note: 0X{checksum_addr} is not valid according to spec above
+
+	var res []struct {
+		A     MixedcaseAddress
+		Valid bool
+	}
+	if err := json.Unmarshal([]byte(`[
+		{"A" : "0xae967917c465db8578ca9024c205720b1a3651A9", "Valid": false},
+		{"A" : "0xAe967917c465db8578ca9024c205720b1a3651A9", "Valid": true},
+		{"A" : "0XAe967917c465db8578ca9024c205720b1a3651A9", "Valid": false},
+		{"A" : "0x1111111111111111111112222222222223333323", "Valid": true}
+		]`), &res); err != nil {
+		t.Fatal(err)
+	}
+
+	for _, r := range res {
+		if got := r.A.ValidChecksum(); got != r.Valid {
+			t.Errorf("Expected checksum %v, got checksum %v, input %v", r.Valid, got, r.A.String())
+		}
+	}
+
+	//These should throw exceptions:
+	var r2 []MixedcaseAddress
+	for _, r := range []string{
+		`["0x11111111111111111111122222222222233333"]`,     // Too short
+		`["0x111111111111111111111222222222222333332"]`,    // Too short
+		`["0x11111111111111111111122222222222233333234"]`,  // Too long
+		`["0x111111111111111111111222222222222333332344"]`, // Too long
+		`["1111111111111111111112222222222223333323"]`,     // Missing 0x
+		`["x1111111111111111111112222222222223333323"]`,    // Missing 0
+		`["0xG111111111111111111112222222222223333323"]`,   //Non-hex
+	} {
+		if err := json.Unmarshal([]byte(r), &r2); err == nil {
+			t.Errorf("Expected failure, input %v", r)
+		}
+
+	}
+
+}
+
+func TestHash_Scan(t *testing.T) {
+	type args struct {
+		src interface{}
+	}
+	tests := []struct {
+		name    string
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "working scan",
+			args: args{src: []byte{
+				0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
+				0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
+				0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
+				0x10, 0x00,
+			}},
+			wantErr: false,
+		},
+		{
+			name:    "non working scan",
+			args:    args{src: int64(1234567890)},
+			wantErr: true,
+		},
+		{
+			name: "invalid length scan",
+			args: args{src: []byte{
+				0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
+				0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
+				0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
+			}},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			h := &Hash{}
+			if err := h.Scan(tt.args.src); (err != nil) != tt.wantErr {
+				t.Errorf("Hash.Scan() error = %v, wantErr %v", err, tt.wantErr)
+			}
+
+			if !tt.wantErr {
+				for i := range h {
+					if h[i] != tt.args.src.([]byte)[i] {
+						t.Errorf(
+							"Hash.Scan() didn't scan the %d src correctly (have %X, want %X)",
+							i, h[i], tt.args.src.([]byte)[i],
+						)
+					}
+				}
+			}
+		})
+	}
+}
+
+func TestHash_Value(t *testing.T) {
+	b := []byte{
+		0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
+		0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
+		0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
+		0x10, 0x00,
+	}
+	var usedH Hash
+	usedH.SetBytes(b)
+	tests := []struct {
+		name    string
+		h       Hash
+		want    driver.Value
+		wantErr bool
+	}{
+		{
+			name:    "Working value",
+			h:       usedH,
+			want:    b,
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := tt.h.Value()
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Hash.Value() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("Hash.Value() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestAddress_Scan(t *testing.T) {
+	type args struct {
+		src interface{}
+	}
+	tests := []struct {
+		name    string
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "working scan",
+			args: args{src: []byte{
+				0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
+				0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
+			}},
+			wantErr: false,
+		},
+		{
+			name:    "non working scan",
+			args:    args{src: int64(1234567890)},
+			wantErr: true,
+		},
+		{
+			name: "invalid length scan",
+			args: args{src: []byte{
+				0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
+				0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a,
+			}},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			a := &Address{}
+			if err := a.Scan(tt.args.src); (err != nil) != tt.wantErr {
+				t.Errorf("Address.Scan() error = %v, wantErr %v", err, tt.wantErr)
+			}
+
+			if !tt.wantErr {
+				for i := range a {
+					if a[i] != tt.args.src.([]byte)[i] {
+						t.Errorf(
+							"Address.Scan() didn't scan the %d src correctly (have %X, want %X)",
+							i, a[i], tt.args.src.([]byte)[i],
+						)
+					}
+				}
+			}
+		})
+	}
+}
+
+func TestAddress_Value(t *testing.T) {
+	b := []byte{
+		0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
+		0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
+	}
+	var usedA Address
+	usedA.SetBytes(b)
+	tests := []struct {
+		name    string
+		a       Address
+		want    driver.Value
+		wantErr bool
+	}{
+		{
+			name:    "Working value",
+			a:       usedA,
+			want:    b,
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := tt.a.Value()
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Address.Value() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("Address.Value() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestAddress_Format(t *testing.T) {
+	b := []byte{
+		0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
+		0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
+	}
+	var addr Address
+	addr.SetBytes(b)
+
+	tests := []struct {
+		name string
+		out  string
+		want string
+	}{
+		{
+			name: "println",
+			out:  fmt.Sprintln(addr),
+			want: "0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15\n",
+		},
+		{
+			name: "print",
+			out:  fmt.Sprint(addr),
+			want: "0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15",
+		},
+		{
+			name: "printf-s",
+			out: func() string {
+				buf := new(bytes.Buffer)
+				fmt.Fprintf(buf, "%s", addr)
+				return buf.String()
+			}(),
+			want: "0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15",
+		},
+		{
+			name: "printf-q",
+			out:  fmt.Sprintf("%q", addr),
+			want: `"0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15"`,
+		},
+		{
+			name: "printf-x",
+			out:  fmt.Sprintf("%x", addr),
+			want: "b26f2b342aab24bcf63ea218c6a9274d30ab9a15",
+		},
+		{
+			name: "printf-X",
+			out:  fmt.Sprintf("%X", addr),
+			want: "B26F2B342AAB24BCF63EA218C6A9274D30AB9A15",
+		},
+		{
+			name: "printf-#x",
+			out:  fmt.Sprintf("%#x", addr),
+			want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15",
+		},
+		{
+			name: "printf-v",
+			out:  fmt.Sprintf("%v", addr),
+			want: "0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15",
+		},
+		// The original default formatter for byte slice
+		{
+			name: "printf-d",
+			out:  fmt.Sprintf("%d", addr),
+			want: "[178 111 43 52 42 171 36 188 246 62 162 24 198 169 39 77 48 171 154 21]",
+		},
+		// Invalid format char.
+		{
+			name: "printf-t",
+			out:  fmt.Sprintf("%t", addr),
+			want: "%!t(address=b26f2b342aab24bcf63ea218c6a9274d30ab9a15)",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if tt.out != tt.want {
+				t.Errorf("%s does not render as expected:\n got %s\nwant %s", tt.name, tt.out, tt.want)
+			}
+		})
+	}
+}
+
+func TestHash_Format(t *testing.T) {
+	var hash Hash
+	hash.SetBytes([]byte{
+		0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
+		0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
+		0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
+		0x10, 0x00,
+	})
+
+	tests := []struct {
+		name string
+		out  string
+		want string
+	}{
+		{
+			name: "println",
+			out:  fmt.Sprintln(hash),
+			want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000\n",
+		},
+		{
+			name: "print",
+			out:  fmt.Sprint(hash),
+			want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
+		},
+		{
+			name: "printf-s",
+			out: func() string {
+				buf := new(bytes.Buffer)
+				fmt.Fprintf(buf, "%s", hash)
+				return buf.String()
+			}(),
+			want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
+		},
+		{
+			name: "printf-q",
+			out:  fmt.Sprintf("%q", hash),
+			want: `"0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000"`,
+		},
+		{
+			name: "printf-x",
+			out:  fmt.Sprintf("%x", hash),
+			want: "b26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
+		},
+		{
+			name: "printf-X",
+			out:  fmt.Sprintf("%X", hash),
+			want: "B26F2B342AAB24BCF63EA218C6A9274D30AB9A15A218C6A9274D30AB9A151000",
+		},
+		{
+			name: "printf-#x",
+			out:  fmt.Sprintf("%#x", hash),
+			want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
+		},
+		{
+			name: "printf-#X",
+			out:  fmt.Sprintf("%#X", hash),
+			want: "0XB26F2B342AAB24BCF63EA218C6A9274D30AB9A15A218C6A9274D30AB9A151000",
+		},
+		{
+			name: "printf-v",
+			out:  fmt.Sprintf("%v", hash),
+			want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
+		},
+		// The original default formatter for byte slice
+		{
+			name: "printf-d",
+			out:  fmt.Sprintf("%d", hash),
+			want: "[178 111 43 52 42 171 36 188 246 62 162 24 198 169 39 77 48 171 154 21 162 24 198 169 39 77 48 171 154 21 16 0]",
+		},
+		// Invalid format char.
+		{
+			name: "printf-t",
+			out:  fmt.Sprintf("%t", hash),
+			want: "%!t(hash=b26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000)",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if tt.out != tt.want {
+				t.Errorf("%s does not render as expected:\n got %s\nwant %s", tt.name, tt.out, tt.want)
+			}
+		})
+	}
+}

+ 11 - 0
go.mod

@@ -0,0 +1,11 @@
+module blockchain-go
+
+go 1.18
+
+require (
+	github.com/go-stack/stack v1.8.1
+	github.com/panjf2000/ants/v2 v2.7.2
+	golang.org/x/crypto v0.7.0
+)
+
+require golang.org/x/sys v0.6.0 // indirect

+ 26 - 0
go.sum

@@ -0,0 +1,26 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
+github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
+github.com/panjf2000/ants/v2 v2.7.2 h1:2NUt9BaZFO5kQzrieOmK/wdb/tQ/K+QHaxN8sOgD63U=
+github.com/panjf2000/ants/v2 v2.7.2/go.mod h1:KIBmYG9QQX5U2qzFP/yQJaq/nSb6rahS9iEHkrCMgM8=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
+golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 11 - 0
log/CONTRIBUTORS

@@ -0,0 +1,11 @@
+Contributors to log15:
+
+- Aaron L 
+- Alan Shreve 
+- Chris Hines 
+- Ciaran Downey 
+- Dmitry Chestnykh 
+- Evan Shaw 
+- Péter Szilágyi 
+- Trevor Gattis 
+- Vincent Vanackere 

+ 13 - 0
log/LICENSE

@@ -0,0 +1,13 @@
+Copyright 2014 Alan Shreve
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 77 - 0
log/README.md

@@ -0,0 +1,77 @@
+![obligatory xkcd](https://imgs.xkcd.com/comics/standards.png)
+
+# log15 [![godoc reference](https://godoc.org/github.com/inconshreveable/log15?status.png)](https://godoc.org/github.com/inconshreveable/log15) [![Build Status](https://travis-ci.org/inconshreveable/log15.svg?branch=master)](https://travis-ci.org/inconshreveable/log15)
+
+Package log15 provides an opinionated, simple toolkit for best-practice logging in Go (golang) that is both human and machine readable. It is modeled after the Go standard library's [`io`](https://golang.org/pkg/io/) and [`net/http`](https://golang.org/pkg/net/http/) packages and is an alternative to the standard library's [`log`](https://golang.org/pkg/log/) package.
+
+## Features
+- A simple, easy-to-understand API
+- Promotes structured logging by encouraging use of key/value pairs
+- Child loggers which inherit and add their own private context
+- Lazy evaluation of expensive operations
+- Simple Handler interface allowing for construction of flexible, custom logging configurations with a tiny API.
+- Color terminal support
+- Built-in support for logging to files, streams, syslog, and the network
+- Support for forking records to multiple handlers, buffering records for output, failing over from failed handler writes, + more
+
+## Versioning
+The API of the master branch of log15 should always be considered unstable. If you want to rely on a stable API,
+you must vendor the library.
+
+## Importing
+
+```go
+import log "github.com/inconshreveable/log15"
+```
+
+## Examples
+
+```go
+// all loggers can have key/value context
+srvlog := log.New("module", "app/server")
+
+// all log messages can have key/value context
+srvlog.Warn("abnormal conn rate", "rate", curRate, "low", lowRate, "high", highRate)
+
+// child loggers with inherited context
+connlog := srvlog.New("raddr", c.RemoteAddr())
+connlog.Info("connection open")
+
+// lazy evaluation
+connlog.Debug("ping remote", "latency", log.Lazy{pingRemote})
+
+// flexible configuration
+srvlog.SetHandler(log.MultiHandler(
+    log.StreamHandler(os.Stderr, log.LogfmtFormat()),
+    log.LvlFilterHandler(
+        log.LvlError,
+        log.Must.FileHandler("errors.json", log.JSONFormat()))))
+```
+
+Will result in output that looks like this:
+
+```
+WARN[06-17|21:58:10] abnormal conn rate                       module=app/server rate=0.500 low=0.100 high=0.800
+INFO[06-17|21:58:10] connection open                          module=app/server raddr=10.0.0.1
+```
+
+## Breaking API Changes
+The following commits broke API stability. This reference is intended to help you understand the consequences of updating to a newer version
+of log15.
+
+- 57a084d014d4150152b19e4e531399a7145d1540 - Added a `Get()` method to the `Logger` interface to retrieve the current handler
+- 93404652ee366648fa622b64d1e2b67d75a3094a - `Record` field `Call` changed to `stack.Call` with switch to `github.com/go-stack/stack`
+- a5e7613673c73281f58e15a87d2cf0cf111e8152 - Restored `syslog.Priority` argument to the `SyslogXxx` handler constructors
+
+## FAQ
+
+### The varargs style is brittle and error prone! Can I have type safety please?
+Yes. Use `log.Ctx`:
+
+```go
+srvlog := log.New(log.Ctx{"module": "app/server"})
+srvlog.Warn("abnormal conn rate", log.Ctx{"rate": curRate, "low": lowRate, "high": highRate})
+```
+
+## License
+Apache

+ 5 - 0
log/README_ETHEREUM.md

@@ -0,0 +1,5 @@
+This package is a fork of https://github.com/inconshreveable/log15, with some
+minor modifications required by the go-ethereum codebase:
+
+ * Support for log level `trace`
+ * Modified behavior to exit on `critical` failure

+ 214 - 0
log/async_file_writer.go

@@ -0,0 +1,214 @@
+package log
+
+import (
+	"errors"
+	"fmt"
+	"os"
+	"path/filepath"
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+type HourTicker struct {
+	stop chan struct{}
+	C    <-chan time.Time
+}
+
+func NewHourTicker() *HourTicker {
+	ht := &HourTicker{
+		stop: make(chan struct{}),
+	}
+	ht.C = ht.Ticker()
+	return ht
+}
+
+func (ht *HourTicker) Stop() {
+	ht.stop <- struct{}{}
+}
+
+func (ht *HourTicker) Ticker() <-chan time.Time {
+	ch := make(chan time.Time)
+	go func() {
+		hour := time.Now().Hour()
+		ticker := time.NewTicker(time.Second)
+		defer ticker.Stop()
+		for {
+			select {
+			case t := <-ticker.C:
+				if t.Hour() != hour {
+					ch <- t
+					hour = t.Hour()
+				}
+			case <-ht.stop:
+				return
+			}
+		}
+	}()
+	return ch
+}
+
+type AsyncFileWriter struct {
+	filePath string
+	fd       *os.File
+
+	wg         sync.WaitGroup
+	started    int32
+	buf        chan []byte
+	stop       chan struct{}
+	hourTicker *HourTicker
+}
+
+func NewAsyncFileWriter(filePath string, bufSize int64) *AsyncFileWriter {
+	absFilePath, err := filepath.Abs(filePath)
+	if err != nil {
+		panic(fmt.Sprintf("get file path of logger error. filePath=%s, err=%s", filePath, err))
+	}
+
+	return &AsyncFileWriter{
+		filePath:   absFilePath,
+		buf:        make(chan []byte, bufSize),
+		stop:       make(chan struct{}),
+		hourTicker: NewHourTicker(),
+	}
+}
+
+func (w *AsyncFileWriter) initLogFile() error {
+	var (
+		fd  *os.File
+		err error
+	)
+
+	realFilePath := w.timeFilePath(w.filePath)
+	fd, err = os.OpenFile(realFilePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
+	if err != nil {
+		return err
+	}
+
+	w.fd = fd
+	_, err = os.Lstat(w.filePath)
+	if err == nil || os.IsExist(err) {
+		err = os.Remove(w.filePath)
+		if err != nil {
+			return err
+		}
+	}
+
+	err = os.Symlink(realFilePath, w.filePath)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (w *AsyncFileWriter) Start() error {
+	if !atomic.CompareAndSwapInt32(&w.started, 0, 1) {
+		return errors.New("logger has already been started")
+	}
+
+	err := w.initLogFile()
+	if err != nil {
+		return err
+	}
+
+	w.wg.Add(1)
+	go func() {
+		defer func() {
+			atomic.StoreInt32(&w.started, 0)
+
+			w.flushBuffer()
+			w.flushAndClose()
+
+			w.wg.Done()
+		}()
+
+		for {
+			select {
+			case msg, ok := <-w.buf:
+				if !ok {
+					fmt.Fprintln(os.Stderr, "buf channel has been closed.")
+					return
+				}
+				w.SyncWrite(msg)
+			case <-w.stop:
+				return
+			}
+		}
+	}()
+	return nil
+}
+
+func (w *AsyncFileWriter) flushBuffer() {
+	for {
+		select {
+		case msg := <-w.buf:
+			w.SyncWrite(msg)
+		default:
+			return
+		}
+	}
+}
+
+func (w *AsyncFileWriter) SyncWrite(msg []byte) {
+	w.rotateFile()
+	if w.fd != nil {
+		w.fd.Write(msg)
+	}
+}
+
+func (w *AsyncFileWriter) rotateFile() {
+	select {
+	case <-w.hourTicker.C:
+		if err := w.flushAndClose(); err != nil {
+			fmt.Fprintf(os.Stderr, "flush and close file error. err=%s", err)
+		}
+		if err := w.initLogFile(); err != nil {
+			fmt.Fprintf(os.Stderr, "init log file error. err=%s", err)
+		}
+	default:
+	}
+}
+
+func (w *AsyncFileWriter) Stop() {
+	w.stop <- struct{}{}
+	w.wg.Wait()
+
+	w.hourTicker.Stop()
+}
+
+func (w *AsyncFileWriter) Write(msg []byte) (n int, err error) {
+	// TODO(wuzhenxing): for the underlying array may change, is there a better way to avoid copying slice?
+	buf := make([]byte, len(msg))
+	copy(buf, msg)
+
+	select {
+	case w.buf <- buf:
+	default:
+	}
+	return 0, nil
+}
+
+func (w *AsyncFileWriter) Flush() error {
+	if w.fd == nil {
+		return nil
+	}
+	return w.fd.Sync()
+}
+
+func (w *AsyncFileWriter) flushAndClose() error {
+	if w.fd == nil {
+		return nil
+	}
+
+	err := w.fd.Sync()
+	if err != nil {
+		return err
+	}
+
+	return w.fd.Close()
+}
+
+func (w *AsyncFileWriter) timeFilePath(filePath string) string {
+	return filePath + "." + time.Now().Format("2006-01-02_15")
+}

+ 26 - 0
log/async_file_writer_test.go

@@ -0,0 +1,26 @@
+package log
+
+import (
+	"io/ioutil"
+	"os"
+	"strings"
+	"testing"
+)
+
+func TestWriter(t *testing.T) {
+	w := NewAsyncFileWriter("./hello.log", 100)
+	w.Start()
+	w.Write([]byte("hello\n"))
+	w.Write([]byte("world\n"))
+	w.Stop()
+	files, _ := ioutil.ReadDir("./")
+	for _, f := range files {
+		fn := f.Name()
+		if strings.HasPrefix(fn, "hello") {
+			t.Log(fn)
+			content, _ := ioutil.ReadFile(fn)
+			t.Log(content)
+			os.Remove(fn)
+		}
+	}
+}

+ 333 - 0
log/doc.go

@@ -0,0 +1,333 @@
+/*
+Package log15 provides an opinionated, simple toolkit for best-practice logging that is
+both human and machine readable. It is modeled after the standard library's io and net/http
+packages.
+
+This package enforces you to only log key/value pairs. Keys must be strings. Values may be
+any type that you like. The default output format is logfmt, but you may also choose to use
+JSON instead if that suits you. Here's how you log:
+
+    log.Info("page accessed", "path", r.URL.Path, "user_id", user.id)
+
+This will output a line that looks like:
+
+     lvl=info t=2014-05-02T16:07:23-0700 msg="page accessed" path=/org/71/profile user_id=9
+
+Getting Started
+
+To get started, you'll want to import the library:
+
+    import log "github.com/inconshreveable/log15"
+
+
+Now you're ready to start logging:
+
+    func main() {
+        log.Info("Program starting", "args", os.Args())
+    }
+
+
+Convention
+
+Because recording a human-meaningful message is common and good practice, the first argument to every
+logging method is the value to the *implicit* key 'msg'.
+
+Additionally, the level you choose for a message will be automatically added with the key 'lvl', and so
+will the current timestamp with key 't'.
+
+You may supply any additional context as a set of key/value pairs to the logging function. log15 allows
+you to favor terseness, ordering, and speed over safety. This is a reasonable tradeoff for
+logging functions. You don't need to explicitly state keys/values, log15 understands that they alternate
+in the variadic argument list:
+
+    log.Warn("size out of bounds", "low", lowBound, "high", highBound, "val", val)
+
+If you really do favor your type-safety, you may choose to pass a log.Ctx instead:
+
+    log.Warn("size out of bounds", log.Ctx{"low": lowBound, "high": highBound, "val": val})
+
+
+Context loggers
+
+Frequently, you want to add context to a logger so that you can track actions associated with it. An http
+request is a good example. You can easily create new loggers that have context that is automatically included
+with each log line:
+
+    requestlogger := log.New("path", r.URL.Path)
+
+    // later
+    requestlogger.Debug("db txn commit", "duration", txnTimer.Finish())
+
+This will output a log line that includes the path context that is attached to the logger:
+
+    lvl=dbug t=2014-05-02T16:07:23-0700 path=/repo/12/add_hook msg="db txn commit" duration=0.12
+
+
+Handlers
+
+The Handler interface defines where log lines are printed to and how they are formatted. Handler is a
+single interface that is inspired by net/http's handler interface:
+
+    type Handler interface {
+        Log(r *Record) error
+    }
+
+
+Handlers can filter records, format them, or dispatch to multiple other Handlers.
+This package implements a number of Handlers for common logging patterns that are
+easily composed to create flexible, custom logging structures.
+
+Here's an example handler that prints logfmt output to Stdout:
+
+    handler := log.StreamHandler(os.Stdout, log.LogfmtFormat())
+
+Here's an example handler that defers to two other handlers. One handler only prints records
+from the rpc package in logfmt to standard out. The other prints records at Error level
+or above in JSON formatted output to the file /var/log/service.json
+
+    handler := log.MultiHandler(
+        log.LvlFilterHandler(log.LvlError, log.Must.FileHandler("/var/log/service.json", log.JSONFormat())),
+        log.MatchFilterHandler("pkg", "app/rpc" log.StdoutHandler())
+    )
+
+Logging File Names and Line Numbers
+
+This package implements three Handlers that add debugging information to the
+context, CallerFileHandler, CallerFuncHandler and CallerStackHandler. Here's
+an example that adds the source file and line number of each logging call to
+the context.
+
+    h := log.CallerFileHandler(log.StdoutHandler)
+    log.Root().SetHandler(h)
+    ...
+    log.Error("open file", "err", err)
+
+This will output a line that looks like:
+
+    lvl=eror t=2014-05-02T16:07:23-0700 msg="open file" err="file not found" caller=data.go:42
+
+Here's an example that logs the call stack rather than just the call site.
+
+    h := log.CallerStackHandler("%+v", log.StdoutHandler)
+    log.Root().SetHandler(h)
+    ...
+    log.Error("open file", "err", err)
+
+This will output a line that looks like:
+
+    lvl=eror t=2014-05-02T16:07:23-0700 msg="open file" err="file not found" stack="[pkg/data.go:42 pkg/cmd/main.go]"
+
+The "%+v" format instructs the handler to include the path of the source file
+relative to the compile time GOPATH. The github.com/go-stack/stack package
+documents the full list of formatting verbs and modifiers available.
+
+Custom Handlers
+
+The Handler interface is so simple that it's also trivial to write your own. Let's create an
+example handler which tries to write to one handler, but if that fails it falls back to
+writing to another handler and includes the error that it encountered when trying to write
+to the primary. This might be useful when trying to log over a network socket, but if that
+fails you want to log those records to a file on disk.
+
+    type BackupHandler struct {
+        Primary Handler
+        Secondary Handler
+    }
+
+    func (h *BackupHandler) Log (r *Record) error {
+        err := h.Primary.Log(r)
+        if err != nil {
+            r.Ctx = append(ctx, "primary_err", err)
+            return h.Secondary.Log(r)
+        }
+        return nil
+    }
+
+This pattern is so useful that a generic version that handles an arbitrary number of Handlers
+is included as part of this library called FailoverHandler.
+
+Logging Expensive Operations
+
+Sometimes, you want to log values that are extremely expensive to compute, but you don't want to pay
+the price of computing them if you haven't turned up your logging level to a high level of detail.
+
+This package provides a simple type to annotate a logging operation that you want to be evaluated
+lazily, just when it is about to be logged, so that it would not be evaluated if an upstream Handler
+filters it out. Just wrap any function which takes no arguments with the log.Lazy type. For example:
+
+    func factorRSAKey() (factors []int) {
+        // return the factors of a very large number
+    }
+
+    log.Debug("factors", log.Lazy{factorRSAKey})
+
+If this message is not logged for any reason (like logging at the Error level), then
+factorRSAKey is never evaluated.
+
+Dynamic context values
+
+The same log.Lazy mechanism can be used to attach context to a logger which you want to be
+evaluated when the message is logged, but not when the logger is created. For example, let's imagine
+a game where you have Player objects:
+
+    type Player struct {
+        name string
+        alive bool
+        log.Logger
+    }
+
+You always want to log a player's name and whether they're alive or dead, so when you create the player
+object, you might do:
+
+    p := &Player{name: name, alive: true}
+    p.Logger = log.New("name", p.name, "alive", p.alive)
+
+Only now, even after a player has died, the logger will still report they are alive because the logging
+context is evaluated when the logger was created. By using the Lazy wrapper, we can defer the evaluation
+of whether the player is alive or not to each log message, so that the log records will reflect the player's
+current state no matter when the log message is written:
+
+    p := &Player{name: name, alive: true}
+    isAlive := func() bool { return p.alive }
+    player.Logger = log.New("name", p.name, "alive", log.Lazy{isAlive})
+
+Terminal Format
+
+If log15 detects that stdout is a terminal, it will configure the default
+handler for it (which is log.StdoutHandler) to use TerminalFormat. This format
+logs records nicely for your terminal, including color-coded output based
+on log level.
+
+Error Handling
+
+Becasuse log15 allows you to step around the type system, there are a few ways you can specify
+invalid arguments to the logging functions. You could, for example, wrap something that is not
+a zero-argument function with log.Lazy or pass a context key that is not a string. Since logging libraries
+are typically the mechanism by which errors are reported, it would be onerous for the logging functions
+to return errors. Instead, log15 handles errors by making these guarantees to you:
+
+- Any log record containing an error will still be printed with the error explained to you as part of the log record.
+
+- Any log record containing an error will include the context key LOG15_ERROR, enabling you to easily
+(and if you like, automatically) detect if any of your logging calls are passing bad values.
+
+Understanding this, you might wonder why the Handler interface can return an error value in its Log method. Handlers
+are encouraged to return errors only if they fail to write their log records out to an external source like if the
+syslog daemon is not responding. This allows the construction of useful handlers which cope with those failures
+like the FailoverHandler.
+
+Library Use
+
+log15 is intended to be useful for library authors as a way to provide configurable logging to
+users of their library. Best practice for use in a library is to always disable all output for your logger
+by default and to provide a public Logger instance that consumers of your library can configure. Like so:
+
+    package yourlib
+
+    import "github.com/inconshreveable/log15"
+
+    var Log = log.New()
+
+    func init() {
+        Log.SetHandler(log.DiscardHandler())
+    }
+
+Users of your library may then enable it if they like:
+
+    import "github.com/inconshreveable/log15"
+    import "example.com/yourlib"
+
+    func main() {
+        handler := // custom handler setup
+        yourlib.Log.SetHandler(handler)
+    }
+
+Best practices attaching logger context
+
+The ability to attach context to a logger is a powerful one. Where should you do it and why?
+I favor embedding a Logger directly into any persistent object in my application and adding
+unique, tracing context keys to it. For instance, imagine I am writing a web browser:
+
+    type Tab struct {
+        url string
+        render *RenderingContext
+        // ...
+
+        Logger
+    }
+
+    func NewTab(url string) *Tab {
+        return &Tab {
+            // ...
+            url: url,
+
+            Logger: log.New("url", url),
+        }
+    }
+
+When a new tab is created, I assign a logger to it with the url of
+the tab as context so it can easily be traced through the logs.
+Now, whenever we perform any operation with the tab, we'll log with its
+embedded logger and it will include the tab title automatically:
+
+    tab.Debug("moved position", "idx", tab.idx)
+
+There's only one problem. What if the tab url changes? We could
+use log.Lazy to make sure the current url is always written, but that
+would mean that we couldn't trace a tab's full lifetime through our
+logs after the user navigate to a new URL.
+
+Instead, think about what values to attach to your loggers the
+same way you think about what to use as a key in a SQL database schema.
+If it's possible to use a natural key that is unique for the lifetime of the
+object, do so. But otherwise, log15's ext package has a handy RandId
+function to let you generate what you might call "surrogate keys"
+They're just random hex identifiers to use for tracing. Back to our
+Tab example, we would prefer to set up our Logger like so:
+
+        import logext "github.com/inconshreveable/log15/ext"
+
+        t := &Tab {
+            // ...
+            url: url,
+        }
+
+        t.Logger = log.New("id", logext.RandId(8), "url", log.Lazy{t.getUrl})
+        return t
+
+Now we'll have a unique traceable identifier even across loading new urls, but
+we'll still be able to see the tab's current url in the log messages.
+
+Must
+
+For all Handler functions which can return an error, there is a version of that
+function which will return no error but panics on failure. They are all available
+on the Must object. For example:
+
+    log.Must.FileHandler("/path", log.JSONFormat)
+    log.Must.NetHandler("tcp", ":1234", log.JSONFormat)
+
+Inspiration and Credit
+
+All of the following excellent projects inspired the design of this library:
+
+code.google.com/p/log4go
+
+github.com/op/go-logging
+
+github.com/technoweenie/grohl
+
+github.com/Sirupsen/logrus
+
+github.com/kr/logfmt
+
+github.com/spacemonkeygo/spacelog
+
+golang's stdlib, notably io and net/http
+
+The Name
+
+https://xkcd.com/927/
+
+*/
+package log

+ 486 - 0
log/format.go

@@ -0,0 +1,486 @@
+package log
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"math/big"
+	"reflect"
+	"strconv"
+	"strings"
+	"sync"
+	"sync/atomic"
+	"time"
+	"unicode/utf8"
+)
+
+const (
+	timeFormat        = "2006-01-02T15:04:05-0700"
+	termTimeFormat    = "01-02|15:04:05.000"
+	floatFormat       = 'f'
+	termMsgJust       = 40
+	termCtxMaxPadding = 40
+)
+
+// locationTrims are trimmed for display to avoid unwieldy log lines.
+var locationTrims = []string{
+	"github.com/ethereum/go-ethereum/",
+}
+
+// PrintOrigins sets or unsets log location (file:line) printing for terminal
+// format output.
+func PrintOrigins(print bool) {
+	if print {
+		atomic.StoreUint32(&locationEnabled, 1)
+	} else {
+		atomic.StoreUint32(&locationEnabled, 0)
+	}
+}
+
+// locationEnabled is an atomic flag controlling whether the terminal formatter
+// should append the log locations too when printing entries.
+var locationEnabled uint32
+
+// locationLength is the maxmimum path length encountered, which all logs are
+// padded to to aid in alignment.
+var locationLength uint32
+
+// fieldPadding is a global map with maximum field value lengths seen until now
+// to allow padding log contexts in a bit smarter way.
+var fieldPadding = make(map[string]int)
+
+// fieldPaddingLock is a global mutex protecting the field padding map.
+var fieldPaddingLock sync.RWMutex
+
+type Format interface {
+	Format(r *Record) []byte
+}
+
+// FormatFunc returns a new Format object which uses
+// the given function to perform record formatting.
+func FormatFunc(f func(*Record) []byte) Format {
+	return formatFunc(f)
+}
+
+type formatFunc func(*Record) []byte
+
+func (f formatFunc) Format(r *Record) []byte {
+	return f(r)
+}
+
+// TerminalStringer is an analogous interface to the stdlib stringer, allowing
+// own types to have custom shortened serialization formats when printed to the
+// screen.
+type TerminalStringer interface {
+	TerminalString() string
+}
+
+// TerminalFormat formats log records optimized for human readability on
+// a terminal with color-coded level output and terser human friendly timestamp.
+// This format should only be used for interactive programs or while developing.
+//
+//     [LEVEL] [TIME] MESSAGE key=value key=value ...
+//
+// Example:
+//
+//     [DBUG] [May 16 20:58:45] remove route ns=haproxy addr=127.0.0.1:50002
+//
+func TerminalFormat(usecolor bool) Format {
+	return FormatFunc(func(r *Record) []byte {
+		var color = 0
+		if usecolor {
+			switch r.Lvl {
+			case LvlCrit:
+				color = 35
+			case LvlError:
+				color = 31
+			case LvlWarn:
+				color = 33
+			case LvlInfo:
+				color = 32
+			case LvlDebug:
+				color = 36
+			case LvlTrace:
+				color = 34
+			}
+		}
+
+		b := &bytes.Buffer{}
+		lvl := r.Lvl.AlignedString()
+		if atomic.LoadUint32(&locationEnabled) != 0 {
+			// Log origin printing was requested, format the location path and line number
+			location := fmt.Sprintf("%+v", r.Call)
+			for _, prefix := range locationTrims {
+				location = strings.TrimPrefix(location, prefix)
+			}
+			// Maintain the maximum location length for fancyer alignment
+			align := int(atomic.LoadUint32(&locationLength))
+			if align < len(location) {
+				align = len(location)
+				atomic.StoreUint32(&locationLength, uint32(align))
+			}
+			padding := strings.Repeat(" ", align-len(location))
+
+			// Assemble and print the log heading
+			if color > 0 {
+				fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s|%s]%s %s ", color, lvl, r.Time.Format(termTimeFormat), location, padding, r.Msg)
+			} else {
+				fmt.Fprintf(b, "%s[%s|%s]%s %s ", lvl, r.Time.Format(termTimeFormat), location, padding, r.Msg)
+			}
+		} else {
+			if color > 0 {
+				fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %s ", color, lvl, r.Time.Format(termTimeFormat), r.Msg)
+			} else {
+				fmt.Fprintf(b, "%s[%s] %s ", lvl, r.Time.Format(termTimeFormat), r.Msg)
+			}
+		}
+		// try to justify the log output for short messages
+		length := utf8.RuneCountInString(r.Msg)
+		if len(r.Ctx) > 0 && length < termMsgJust {
+			b.Write(bytes.Repeat([]byte{' '}, termMsgJust-length))
+		}
+		// print the keys logfmt style
+		logfmt(b, r.Ctx, color, true)
+		return b.Bytes()
+	})
+}
+
+// LogfmtFormat prints records in logfmt format, an easy machine-parseable but human-readable
+// format for key/value pairs.
+//
+// For more details see: http://godoc.org/github.com/kr/logfmt
+//
+func LogfmtFormat() Format {
+	return FormatFunc(func(r *Record) []byte {
+		common := []interface{}{r.KeyNames.Time, r.Time, r.KeyNames.Lvl, r.Lvl, r.KeyNames.Msg, r.Msg}
+		buf := &bytes.Buffer{}
+		logfmt(buf, append(common, r.Ctx...), 0, false)
+		return buf.Bytes()
+	})
+}
+
+func logfmt(buf *bytes.Buffer, ctx []interface{}, color int, term bool) {
+	for i := 0; i < len(ctx); i += 2 {
+		if i != 0 {
+			buf.WriteByte(' ')
+		}
+
+		k, ok := ctx[i].(string)
+		v := formatLogfmtValue(ctx[i+1], term)
+		if !ok {
+			k, v = errorKey, formatLogfmtValue(k, term)
+		}
+
+		// XXX: we should probably check that all of your key bytes aren't invalid
+		fieldPaddingLock.RLock()
+		padding := fieldPadding[k]
+		fieldPaddingLock.RUnlock()
+
+		length := utf8.RuneCountInString(v)
+		if padding < length && length <= termCtxMaxPadding {
+			padding = length
+
+			fieldPaddingLock.Lock()
+			fieldPadding[k] = padding
+			fieldPaddingLock.Unlock()
+		}
+		if color > 0 {
+			fmt.Fprintf(buf, "\x1b[%dm%s\x1b[0m=", color, k)
+		} else {
+			buf.WriteString(k)
+			buf.WriteByte('=')
+		}
+		buf.WriteString(v)
+		if i < len(ctx)-2 && padding > length {
+			buf.Write(bytes.Repeat([]byte{' '}, padding-length))
+		}
+	}
+	buf.WriteByte('\n')
+}
+
+// JSONFormat formats log records as JSON objects separated by newlines.
+// It is the equivalent of JSONFormatEx(false, true).
+func JSONFormat() Format {
+	return JSONFormatEx(false, true)
+}
+
+// JSONFormatOrderedEx formats log records as JSON arrays. If pretty is true,
+// records will be pretty-printed. If lineSeparated is true, records
+// will be logged with a new line between each record.
+func JSONFormatOrderedEx(pretty, lineSeparated bool) Format {
+	jsonMarshal := json.Marshal
+	if pretty {
+		jsonMarshal = func(v interface{}) ([]byte, error) {
+			return json.MarshalIndent(v, "", "    ")
+		}
+	}
+	return FormatFunc(func(r *Record) []byte {
+		props := make(map[string]interface{})
+
+		props[r.KeyNames.Time] = r.Time
+		props[r.KeyNames.Lvl] = r.Lvl.String()
+		props[r.KeyNames.Msg] = r.Msg
+
+		ctx := make([]string, len(r.Ctx))
+		for i := 0; i < len(r.Ctx); i += 2 {
+			k, ok := r.Ctx[i].(string)
+			if !ok {
+				props[errorKey] = fmt.Sprintf("%+v is not a string key,", r.Ctx[i])
+			}
+			ctx[i] = k
+			ctx[i+1] = formatLogfmtValue(r.Ctx[i+1], true)
+		}
+		props[r.KeyNames.Ctx] = ctx
+
+		b, err := jsonMarshal(props)
+		if err != nil {
+			b, _ = jsonMarshal(map[string]string{
+				errorKey: err.Error(),
+			})
+			return b
+		}
+		if lineSeparated {
+			b = append(b, '\n')
+		}
+		return b
+	})
+}
+
+// JSONFormatEx formats log records as JSON objects. If pretty is true,
+// records will be pretty-printed. If lineSeparated is true, records
+// will be logged with a new line between each record.
+func JSONFormatEx(pretty, lineSeparated bool) Format {
+	jsonMarshal := json.Marshal
+	if pretty {
+		jsonMarshal = func(v interface{}) ([]byte, error) {
+			return json.MarshalIndent(v, "", "    ")
+		}
+	}
+
+	return FormatFunc(func(r *Record) []byte {
+		props := make(map[string]interface{})
+
+		props[r.KeyNames.Time] = r.Time
+		props[r.KeyNames.Lvl] = r.Lvl.String()
+		props[r.KeyNames.Msg] = r.Msg
+
+		for i := 0; i < len(r.Ctx); i += 2 {
+			k, ok := r.Ctx[i].(string)
+			if !ok {
+				props[errorKey] = fmt.Sprintf("%+v is not a string key", r.Ctx[i])
+			}
+			props[k] = formatJSONValue(r.Ctx[i+1])
+		}
+
+		b, err := jsonMarshal(props)
+		if err != nil {
+			b, _ = jsonMarshal(map[string]string{
+				errorKey: err.Error(),
+			})
+			return b
+		}
+
+		if lineSeparated {
+			b = append(b, '\n')
+		}
+
+		return b
+	})
+}
+
+func formatShared(value interface{}) (result interface{}) {
+	defer func() {
+		if err := recover(); err != nil {
+			if v := reflect.ValueOf(value); v.Kind() == reflect.Ptr && v.IsNil() {
+				result = "nil"
+			} else {
+				panic(err)
+			}
+		}
+	}()
+
+	switch v := value.(type) {
+	case time.Time:
+		return v.Format(timeFormat)
+
+	case error:
+		return v.Error()
+
+	case fmt.Stringer:
+		return v.String()
+
+	default:
+		return v
+	}
+}
+
+func formatJSONValue(value interface{}) interface{} {
+	value = formatShared(value)
+	switch value.(type) {
+	case int, int8, int16, int32, int64, float32, float64, uint, uint8, uint16, uint32, uint64, string:
+		return value
+	default:
+		return fmt.Sprintf("%+v", value)
+	}
+}
+
+// formatValue formats a value for serialization
+func formatLogfmtValue(value interface{}, term bool) string {
+	if value == nil {
+		return "nil"
+	}
+
+	switch v := value.(type) {
+	case time.Time:
+		// Performance optimization: No need for escaping since the provided
+		// timeFormat doesn't have any escape characters, and escaping is
+		// expensive.
+		return v.Format(timeFormat)
+
+	case *big.Int:
+		// Big ints get consumed by the Stringer clause so we need to handle
+		// them earlier on.
+		if v == nil {
+			return "<nil>"
+		}
+		return formatLogfmtBigInt(v)
+	}
+	if term {
+		if s, ok := value.(TerminalStringer); ok {
+			// Custom terminal stringer provided, use that
+			return escapeString(s.TerminalString())
+		}
+	}
+	value = formatShared(value)
+	switch v := value.(type) {
+	case bool:
+		return strconv.FormatBool(v)
+	case float32:
+		return strconv.FormatFloat(float64(v), floatFormat, 3, 64)
+	case float64:
+		return strconv.FormatFloat(v, floatFormat, 3, 64)
+	case int8:
+		return strconv.FormatInt(int64(v), 10)
+	case uint8:
+		return strconv.FormatInt(int64(v), 10)
+	case int16:
+		return strconv.FormatInt(int64(v), 10)
+	case uint16:
+		return strconv.FormatInt(int64(v), 10)
+	// Larger integers get thousands separators.
+	case int:
+		return FormatLogfmtInt64(int64(v))
+	case int32:
+		return FormatLogfmtInt64(int64(v))
+	case int64:
+		return FormatLogfmtInt64(v)
+	case uint:
+		return FormatLogfmtUint64(uint64(v))
+	case uint32:
+		return FormatLogfmtUint64(uint64(v))
+	case uint64:
+		return FormatLogfmtUint64(v)
+	case string:
+		return escapeString(v)
+	default:
+		return escapeString(fmt.Sprintf("%+v", value))
+	}
+}
+
+// FormatLogfmtInt64 formats n with thousand separators.
+func FormatLogfmtInt64(n int64) string {
+	if n < 0 {
+		return formatLogfmtUint64(uint64(-n), true)
+	}
+	return formatLogfmtUint64(uint64(n), false)
+}
+
+// FormatLogfmtUint64 formats n with thousand separators.
+func FormatLogfmtUint64(n uint64) string {
+	return formatLogfmtUint64(n, false)
+}
+
+func formatLogfmtUint64(n uint64, neg bool) string {
+	// Small numbers are fine as is
+	if n < 100000 {
+		if neg {
+			return strconv.Itoa(-int(n))
+		} else {
+			return strconv.Itoa(int(n))
+		}
+	}
+	// Large numbers should be split
+	const maxLength = 26
+
+	var (
+		out   = make([]byte, maxLength)
+		i     = maxLength - 1
+		comma = 0
+	)
+	for ; n > 0; i-- {
+		if comma == 3 {
+			comma = 0
+			out[i] = ','
+		} else {
+			comma++
+			out[i] = '0' + byte(n%10)
+			n /= 10
+		}
+	}
+	if neg {
+		out[i] = '-'
+		i--
+	}
+	return string(out[i+1:])
+}
+
+// formatLogfmtBigInt formats n with thousand separators.
+func formatLogfmtBigInt(n *big.Int) string {
+	if n.IsUint64() {
+		return FormatLogfmtUint64(n.Uint64())
+	}
+	if n.IsInt64() {
+		return FormatLogfmtInt64(n.Int64())
+	}
+
+	var (
+		text  = n.String()
+		buf   = make([]byte, len(text)+len(text)/3)
+		comma = 0
+		i     = len(buf) - 1
+	)
+	for j := len(text) - 1; j >= 0; j, i = j-1, i-1 {
+		c := text[j]
+
+		switch {
+		case c == '-':
+			buf[i] = c
+		case comma == 3:
+			buf[i] = ','
+			i--
+			comma = 0
+			fallthrough
+		default:
+			buf[i] = c
+			comma++
+		}
+	}
+	return string(buf[i+1:])
+}
+
+// escapeString checks if the provided string needs escaping/quoting, and
+// calls strconv.Quote if needed
+func escapeString(s string) string {
+	needsQuoting := false
+	for _, r := range s {
+		// We quote everything below " (0x34) and above~ (0x7E), plus equal-sign
+		if r <= '"' || r > '~' || r == '=' {
+			needsQuoting = true
+			break
+		}
+	}
+	if !needsQuoting {
+		return s
+	}
+	return strconv.Quote(s)
+}

+ 95 - 0
log/format_test.go

@@ -0,0 +1,95 @@
+package log
+
+import (
+	"math"
+	"math/big"
+	"math/rand"
+	"testing"
+)
+
+func TestPrettyInt64(t *testing.T) {
+	tests := []struct {
+		n int64
+		s string
+	}{
+		{0, "0"},
+		{10, "10"},
+		{-10, "-10"},
+		{100, "100"},
+		{-100, "-100"},
+		{1000, "1000"},
+		{-1000, "-1000"},
+		{10000, "10000"},
+		{-10000, "-10000"},
+		{99999, "99999"},
+		{-99999, "-99999"},
+		{100000, "100,000"},
+		{-100000, "-100,000"},
+		{1000000, "1,000,000"},
+		{-1000000, "-1,000,000"},
+		{math.MaxInt64, "9,223,372,036,854,775,807"},
+		{math.MinInt64, "-9,223,372,036,854,775,808"},
+	}
+	for i, tt := range tests {
+		if have := FormatLogfmtInt64(tt.n); have != tt.s {
+			t.Errorf("test %d: format mismatch: have %s, want %s", i, have, tt.s)
+		}
+	}
+}
+
+func TestPrettyUint64(t *testing.T) {
+	tests := []struct {
+		n uint64
+		s string
+	}{
+		{0, "0"},
+		{10, "10"},
+		{100, "100"},
+		{1000, "1000"},
+		{10000, "10000"},
+		{99999, "99999"},
+		{100000, "100,000"},
+		{1000000, "1,000,000"},
+		{math.MaxUint64, "18,446,744,073,709,551,615"},
+	}
+	for i, tt := range tests {
+		if have := FormatLogfmtUint64(tt.n); have != tt.s {
+			t.Errorf("test %d: format mismatch: have %s, want %s", i, have, tt.s)
+		}
+	}
+}
+
+func TestPrettyBigInt(t *testing.T) {
+	tests := []struct {
+		int string
+		s   string
+	}{
+		{"111222333444555678999", "111,222,333,444,555,678,999"},
+		{"-111222333444555678999", "-111,222,333,444,555,678,999"},
+		{"11122233344455567899900", "11,122,233,344,455,567,899,900"},
+		{"-11122233344455567899900", "-11,122,233,344,455,567,899,900"},
+	}
+
+	for _, tt := range tests {
+		v, _ := new(big.Int).SetString(tt.int, 10)
+		if have := formatLogfmtBigInt(v); have != tt.s {
+			t.Errorf("invalid output %s, want %s", have, tt.s)
+		}
+	}
+}
+
+var sink string
+
+func BenchmarkPrettyInt64Logfmt(b *testing.B) {
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		sink = FormatLogfmtInt64(rand.Int63())
+	}
+}
+
+func BenchmarkPrettyUint64Logfmt(b *testing.B) {
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		sink = FormatLogfmtUint64(rand.Uint64())
+	}
+}

+ 375 - 0
log/handler.go

@@ -0,0 +1,375 @@
+package log
+
+import (
+	"fmt"
+	"io"
+	"net"
+	"os"
+	"path"
+	"reflect"
+	"sync"
+
+	"github.com/go-stack/stack"
+)
+
+// Handler defines where and how log records are written.
+// A Logger prints its log records by writing to a Handler.
+// Handlers are composable, providing you great flexibility in combining
+// them to achieve the logging structure that suits your applications.
+type Handler interface {
+	Log(r *Record) error
+}
+
+// FuncHandler returns a Handler that logs records with the given
+// function.
+func FuncHandler(fn func(r *Record) error) Handler {
+	return funcHandler(fn)
+}
+
+type funcHandler func(r *Record) error
+
+func (h funcHandler) Log(r *Record) error {
+	return h(r)
+}
+
+// StreamHandler writes log records to an io.Writer
+// with the given format. StreamHandler can be used
+// to easily begin writing log records to other
+// outputs.
+//
+// StreamHandler wraps itself with LazyHandler and SyncHandler
+// to evaluate Lazy objects and perform safe concurrent writes.
+func StreamHandler(wr io.Writer, fmtr Format) Handler {
+	h := FuncHandler(func(r *Record) error {
+		_, err := wr.Write(fmtr.Format(r))
+		return err
+	})
+	return LazyHandler(SyncHandler(h))
+}
+
+// SyncHandler can be wrapped around a handler to guarantee that
+// only a single Log operation can proceed at a time. It's necessary
+// for thread-safe concurrent writes.
+func SyncHandler(h Handler) Handler {
+	var mu sync.Mutex
+	return FuncHandler(func(r *Record) error {
+		defer mu.Unlock()
+		mu.Lock()
+		return h.Log(r)
+	})
+}
+
+// FileHandler returns a handler which writes log records to the give file
+// using the given format. If the path
+// already exists, FileHandler will append to the given file. If it does not,
+// FileHandler will create the file with mode 0644.
+func FileHandler(path string, fmtr Format) (Handler, error) {
+	f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
+	if err != nil {
+		return nil, err
+	}
+	return closingHandler{f, StreamHandler(f, fmtr)}, nil
+}
+
+// RotatingFileHandler returns a handler which writes log records to file chunks
+// at the given path. When a file's size reaches the limit, the handler creates
+// a new file named after the timestamp of the first log record it will contain.
+func RotatingFileHandler(filePath string, limit uint, formatter Format) (Handler, error) {
+	if _, err := os.Stat(path.Dir(filePath)); os.IsNotExist(err) {
+		err := os.MkdirAll(path.Dir(filePath), 0755)
+		if err != nil {
+			return nil, fmt.Errorf("could not create directory %s, %v", path.Dir(filePath), err)
+		}
+	}
+	fileWriter := NewAsyncFileWriter(filePath, int64(limit))
+	fileWriter.Start()
+	return StreamHandler(fileWriter, formatter), nil
+}
+
+// NetHandler opens a socket to the given address and writes records
+// over the connection.
+func NetHandler(network, addr string, fmtr Format) (Handler, error) {
+	conn, err := net.Dial(network, addr)
+	if err != nil {
+		return nil, err
+	}
+
+	return closingHandler{conn, StreamHandler(conn, fmtr)}, nil
+}
+
+// XXX: closingHandler is essentially unused at the moment
+// it's meant for a future time when the Handler interface supports
+// a possible Close() operation
+type closingHandler struct {
+	io.WriteCloser
+	Handler
+}
+
+func (h *closingHandler) Close() error {
+	return h.WriteCloser.Close()
+}
+
+// CallerFileHandler returns a Handler that adds the line number and file of
+// the calling function to the context with key "caller".
+func CallerFileHandler(h Handler) Handler {
+	return FuncHandler(func(r *Record) error {
+		r.Ctx = append(r.Ctx, "caller", fmt.Sprint(r.Call))
+		return h.Log(r)
+	})
+}
+
+// CallerFuncHandler returns a Handler that adds the calling function name to
+// the context with key "fn".
+func CallerFuncHandler(h Handler) Handler {
+	return FuncHandler(func(r *Record) error {
+		r.Ctx = append(r.Ctx, "fn", formatCall("%+n", r.Call))
+		return h.Log(r)
+	})
+}
+
+// This function is here to please go vet on Go < 1.8.
+func formatCall(format string, c stack.Call) string {
+	return fmt.Sprintf(format, c)
+}
+
+// CallerStackHandler returns a Handler that adds a stack trace to the context
+// with key "stack". The stack trace is formatted as a space separated list of
+// call sites inside matching []'s. The most recent call site is listed first.
+// Each call site is formatted according to format. See the documentation of
+// package github.com/go-stack/stack for the list of supported formats.
+func CallerStackHandler(format string, h Handler) Handler {
+	return FuncHandler(func(r *Record) error {
+		s := stack.Trace().TrimBelow(r.Call).TrimRuntime()
+		if len(s) > 0 {
+			r.Ctx = append(r.Ctx, "stack", fmt.Sprintf(format, s))
+		}
+		return h.Log(r)
+	})
+}
+
+// FilterHandler returns a Handler that only writes records to the
+// wrapped Handler if the given function evaluates true. For example,
+// to only log records where the 'err' key is not nil:
+//
+//    logger.SetHandler(FilterHandler(func(r *Record) bool {
+//        for i := 0; i < len(r.Ctx); i += 2 {
+//            if r.Ctx[i] == "err" {
+//                return r.Ctx[i+1] != nil
+//            }
+//        }
+//        return false
+//    }, h))
+//
+func FilterHandler(fn func(r *Record) bool, h Handler) Handler {
+	return FuncHandler(func(r *Record) error {
+		if fn(r) {
+			return h.Log(r)
+		}
+		return nil
+	})
+}
+
+// MatchFilterHandler returns a Handler that only writes records
+// to the wrapped Handler if the given key in the logged
+// context matches the value. For example, to only log records
+// from your ui package:
+//
+//    log.MatchFilterHandler("pkg", "app/ui", log.StdoutHandler)
+//
+func MatchFilterHandler(key string, value interface{}, h Handler) Handler {
+	return FilterHandler(func(r *Record) (pass bool) {
+		switch key {
+		case r.KeyNames.Lvl:
+			return r.Lvl == value
+		case r.KeyNames.Time:
+			return r.Time == value
+		case r.KeyNames.Msg:
+			return r.Msg == value
+		}
+
+		for i := 0; i < len(r.Ctx); i += 2 {
+			if r.Ctx[i] == key {
+				return r.Ctx[i+1] == value
+			}
+		}
+		return false
+	}, h)
+}
+
+// LvlFilterHandler returns a Handler that only writes
+// records which are less than the given verbosity
+// level to the wrapped Handler. For example, to only
+// log Error/Crit records:
+//
+//     log.LvlFilterHandler(log.LvlError, log.StdoutHandler)
+//
+func LvlFilterHandler(maxLvl Lvl, h Handler) Handler {
+	return FilterHandler(func(r *Record) (pass bool) {
+		return r.Lvl <= maxLvl
+	}, h)
+}
+
+// MultiHandler dispatches any write to each of its handlers.
+// This is useful for writing different types of log information
+// to different locations. For example, to log to a file and
+// standard error:
+//
+//     log.MultiHandler(
+//         log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()),
+//         log.StderrHandler)
+//
+func MultiHandler(hs ...Handler) Handler {
+	return FuncHandler(func(r *Record) error {
+		for _, h := range hs {
+			// what to do about failures?
+			h.Log(r)
+		}
+		return nil
+	})
+}
+
+// FailoverHandler writes all log records to the first handler
+// specified, but will failover and write to the second handler if
+// the first handler has failed, and so on for all handlers specified.
+// For example you might want to log to a network socket, but failover
+// to writing to a file if the network fails, and then to
+// standard out if the file write fails:
+//
+//     log.FailoverHandler(
+//         log.Must.NetHandler("tcp", ":9090", log.JSONFormat()),
+//         log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()),
+//         log.StdoutHandler)
+//
+// All writes that do not go to the first handler will add context with keys of
+// the form "failover_err_{idx}" which explain the error encountered while
+// trying to write to the handlers before them in the list.
+func FailoverHandler(hs ...Handler) Handler {
+	return FuncHandler(func(r *Record) error {
+		var err error
+		for i, h := range hs {
+			err = h.Log(r)
+			if err == nil {
+				return nil
+			}
+			r.Ctx = append(r.Ctx, fmt.Sprintf("failover_err_%d", i), err)
+		}
+
+		return err
+	})
+}
+
+// ChannelHandler writes all records to the given channel.
+// It blocks if the channel is full. Useful for async processing
+// of log messages, it's used by BufferedHandler.
+func ChannelHandler(recs chan<- *Record) Handler {
+	return FuncHandler(func(r *Record) error {
+		recs <- r
+		return nil
+	})
+}
+
+// BufferedHandler writes all records to a buffered
+// channel of the given size which flushes into the wrapped
+// handler whenever it is available for writing. Since these
+// writes happen asynchronously, all writes to a BufferedHandler
+// never return an error and any errors from the wrapped handler are ignored.
+func BufferedHandler(bufSize int, h Handler) Handler {
+	recs := make(chan *Record, bufSize)
+	go func() {
+		for m := range recs {
+			_ = h.Log(m)
+		}
+	}()
+	return ChannelHandler(recs)
+}
+
+// LazyHandler writes all values to the wrapped handler after evaluating
+// any lazy functions in the record's context. It is already wrapped
+// around StreamHandler and SyslogHandler in this library, you'll only need
+// it if you write your own Handler.
+func LazyHandler(h Handler) Handler {
+	return FuncHandler(func(r *Record) error {
+		// go through the values (odd indices) and reassign
+		// the values of any lazy fn to the result of its execution
+		hadErr := false
+		for i := 1; i < len(r.Ctx); i += 2 {
+			lz, ok := r.Ctx[i].(Lazy)
+			if ok {
+				v, err := evaluateLazy(lz)
+				if err != nil {
+					hadErr = true
+					r.Ctx[i] = err
+				} else {
+					if cs, ok := v.(stack.CallStack); ok {
+						v = cs.TrimBelow(r.Call).TrimRuntime()
+					}
+					r.Ctx[i] = v
+				}
+			}
+		}
+
+		if hadErr {
+			r.Ctx = append(r.Ctx, errorKey, "bad lazy")
+		}
+
+		return h.Log(r)
+	})
+}
+
+func evaluateLazy(lz Lazy) (interface{}, error) {
+	t := reflect.TypeOf(lz.Fn)
+
+	if t.Kind() != reflect.Func {
+		return nil, fmt.Errorf("INVALID_LAZY, not func: %+v", lz.Fn)
+	}
+
+	if t.NumIn() > 0 {
+		return nil, fmt.Errorf("INVALID_LAZY, func takes args: %+v", lz.Fn)
+	}
+
+	if t.NumOut() == 0 {
+		return nil, fmt.Errorf("INVALID_LAZY, no func return val: %+v", lz.Fn)
+	}
+
+	value := reflect.ValueOf(lz.Fn)
+	results := value.Call([]reflect.Value{})
+	if len(results) == 1 {
+		return results[0].Interface(), nil
+	}
+	values := make([]interface{}, len(results))
+	for i, v := range results {
+		values[i] = v.Interface()
+	}
+	return values, nil
+}
+
+// DiscardHandler reports success for all writes but does nothing.
+// It is useful for dynamically disabling logging at runtime via
+// a Logger's SetHandler method.
+func DiscardHandler() Handler {
+	return FuncHandler(func(r *Record) error {
+		return nil
+	})
+}
+
+// Must provides the following Handler creation functions
+// which instead of returning an error parameter only return a Handler
+// and panic on failure: FileHandler, NetHandler, SyslogHandler, SyslogNetHandler
+var Must muster
+
+func must(h Handler, err error) Handler {
+	if err != nil {
+		panic(err)
+	}
+	return h
+}
+
+type muster struct{}
+
+func (m muster) FileHandler(path string, fmtr Format) Handler {
+	return must(FileHandler(path, fmtr))
+}
+
+func (m muster) NetHandler(network, addr string, fmtr Format) Handler {
+	return must(NetHandler(network, addr, fmtr))
+}

+ 232 - 0
log/handler_glog.go

@@ -0,0 +1,232 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package log
+
+import (
+	"errors"
+	"fmt"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+	"sync"
+	"sync/atomic"
+)
+
+// errVmoduleSyntax is returned when a user vmodule pattern is invalid.
+var errVmoduleSyntax = errors.New("expect comma-separated list of filename=N")
+
+// errTraceSyntax is returned when a user backtrace pattern is invalid.
+var errTraceSyntax = errors.New("expect file.go:234")
+
+// GlogHandler is a log handler that mimics the filtering features of Google's
+// glog logger: setting global log levels; overriding with callsite pattern
+// matches; and requesting backtraces at certain positions.
+type GlogHandler struct {
+	origin Handler // The origin handler this wraps
+
+	level     uint32 // Current log level, atomically accessible
+	override  uint32 // Flag whether overrides are used, atomically accessible
+	backtrace uint32 // Flag whether backtrace location is set
+
+	patterns  []pattern       // Current list of patterns to override with
+	siteCache map[uintptr]Lvl // Cache of callsite pattern evaluations
+	location  string          // file:line location where to do a stackdump at
+	lock      sync.RWMutex    // Lock protecting the override pattern list
+}
+
+// NewGlogHandler creates a new log handler with filtering functionality similar
+// to Google's glog logger. The returned handler implements Handler.
+func NewGlogHandler(h Handler) *GlogHandler {
+	return &GlogHandler{
+		origin: h,
+	}
+}
+
+// SetHandler updates the handler to write records to the specified sub-handler.
+func (h *GlogHandler) SetHandler(nh Handler) {
+	h.origin = nh
+}
+
+// pattern contains a filter for the Vmodule option, holding a verbosity level
+// and a file pattern to match.
+type pattern struct {
+	pattern *regexp.Regexp
+	level   Lvl
+}
+
+// Verbosity sets the glog verbosity ceiling. The verbosity of individual packages
+// and source files can be raised using Vmodule.
+func (h *GlogHandler) Verbosity(level Lvl) {
+	atomic.StoreUint32(&h.level, uint32(level))
+}
+
+// Vmodule sets the glog verbosity pattern.
+//
+// The syntax of the argument is a comma-separated list of pattern=N, where the
+// pattern is a literal file name or "glob" pattern matching and N is a V level.
+//
+// For instance:
+//
+//  pattern="gopher.go=3"
+//   sets the V level to 3 in all Go files named "gopher.go"
+//
+//  pattern="foo=3"
+//   sets V to 3 in all files of any packages whose import path ends in "foo"
+//
+//  pattern="foo/*=3"
+//   sets V to 3 in all files of any packages whose import path contains "foo"
+func (h *GlogHandler) Vmodule(ruleset string) error {
+	var filter []pattern
+	for _, rule := range strings.Split(ruleset, ",") {
+		// Empty strings such as from a trailing comma can be ignored
+		if len(rule) == 0 {
+			continue
+		}
+		// Ensure we have a pattern = level filter rule
+		parts := strings.Split(rule, "=")
+		if len(parts) != 2 {
+			return errVmoduleSyntax
+		}
+		parts[0] = strings.TrimSpace(parts[0])
+		parts[1] = strings.TrimSpace(parts[1])
+		if len(parts[0]) == 0 || len(parts[1]) == 0 {
+			return errVmoduleSyntax
+		}
+		// Parse the level and if correct, assemble the filter rule
+		level, err := strconv.Atoi(parts[1])
+		if err != nil {
+			return errVmoduleSyntax
+		}
+		if level <= 0 {
+			continue // Ignore. It's harmless but no point in paying the overhead.
+		}
+		// Compile the rule pattern into a regular expression
+		matcher := ".*"
+		for _, comp := range strings.Split(parts[0], "/") {
+			if comp == "*" {
+				matcher += "(/.*)?"
+			} else if comp != "" {
+				matcher += "/" + regexp.QuoteMeta(comp)
+			}
+		}
+		if !strings.HasSuffix(parts[0], ".go") {
+			matcher += "/[^/]+\\.go"
+		}
+		matcher = matcher + "$"
+
+		re, _ := regexp.Compile(matcher)
+		filter = append(filter, pattern{re, Lvl(level)})
+	}
+	// Swap out the vmodule pattern for the new filter system
+	h.lock.Lock()
+	defer h.lock.Unlock()
+
+	h.patterns = filter
+	h.siteCache = make(map[uintptr]Lvl)
+	atomic.StoreUint32(&h.override, uint32(len(filter)))
+
+	return nil
+}
+
+// BacktraceAt sets the glog backtrace location. When set to a file and line
+// number holding a logging statement, a stack trace will be written to the Info
+// log whenever execution hits that statement.
+//
+// Unlike with Vmodule, the ".go" must be present.
+func (h *GlogHandler) BacktraceAt(location string) error {
+	// Ensure the backtrace location contains two non-empty elements
+	parts := strings.Split(location, ":")
+	if len(parts) != 2 {
+		return errTraceSyntax
+	}
+	parts[0] = strings.TrimSpace(parts[0])
+	parts[1] = strings.TrimSpace(parts[1])
+	if len(parts[0]) == 0 || len(parts[1]) == 0 {
+		return errTraceSyntax
+	}
+	// Ensure the .go prefix is present and the line is valid
+	if !strings.HasSuffix(parts[0], ".go") {
+		return errTraceSyntax
+	}
+	if _, err := strconv.Atoi(parts[1]); err != nil {
+		return errTraceSyntax
+	}
+	// All seems valid
+	h.lock.Lock()
+	defer h.lock.Unlock()
+
+	h.location = location
+	atomic.StoreUint32(&h.backtrace, uint32(len(location)))
+
+	return nil
+}
+
+// Log implements Handler.Log, filtering a log record through the global, local
+// and backtrace filters, finally emitting it if either allow it through.
+func (h *GlogHandler) Log(r *Record) error {
+	// If backtracing is requested, check whether this is the callsite
+	if atomic.LoadUint32(&h.backtrace) > 0 {
+		// Everything below here is slow. Although we could cache the call sites the
+		// same way as for vmodule, backtracing is so rare it's not worth the extra
+		// complexity.
+		h.lock.RLock()
+		match := h.location == r.Call.String()
+		h.lock.RUnlock()
+
+		if match {
+			// Callsite matched, raise the log level to info and gather the stacks
+			r.Lvl = LvlInfo
+
+			buf := make([]byte, 1024*1024)
+			buf = buf[:runtime.Stack(buf, true)]
+			r.Msg += "\n\n" + string(buf)
+		}
+	}
+	// If the global log level allows, fast track logging
+	if atomic.LoadUint32(&h.level) >= uint32(r.Lvl) {
+		return h.origin.Log(r)
+	}
+	// If no local overrides are present, fast track skipping
+	if atomic.LoadUint32(&h.override) == 0 {
+		return nil
+	}
+	// Check callsite cache for previously calculated log levels
+	h.lock.RLock()
+	lvl, ok := h.siteCache[r.Call.Frame().PC]
+	h.lock.RUnlock()
+
+	// If we didn't cache the callsite yet, calculate it
+	if !ok {
+		h.lock.Lock()
+		for _, rule := range h.patterns {
+			if rule.pattern.MatchString(fmt.Sprintf("%+s", r.Call)) {
+				h.siteCache[r.Call.Frame().PC], lvl, ok = rule.level, rule.level, true
+				break
+			}
+		}
+		// If no rule matched, remember to drop log the next time
+		if !ok {
+			h.siteCache[r.Call.Frame().PC] = 0
+		}
+		h.lock.Unlock()
+	}
+	if lvl >= r.Lvl {
+		return h.origin.Log(r)
+	}
+	return nil
+}

+ 26 - 0
log/handler_go13.go

@@ -0,0 +1,26 @@
+// +build !go1.4
+
+package log
+
+import (
+	"sync/atomic"
+	"unsafe"
+)
+
+// swapHandler wraps another handler that may be swapped out
+// dynamically at runtime in a thread-safe fashion.
+type swapHandler struct {
+	handler unsafe.Pointer
+}
+
+func (h *swapHandler) Log(r *Record) error {
+	return h.Get().Log(r)
+}
+
+func (h *swapHandler) Get() Handler {
+	return *(*Handler)(atomic.LoadPointer(&h.handler))
+}
+
+func (h *swapHandler) Swap(newHandler Handler) {
+	atomic.StorePointer(&h.handler, unsafe.Pointer(&newHandler))
+}

+ 23 - 0
log/handler_go14.go

@@ -0,0 +1,23 @@
+// +build go1.4
+
+package log
+
+import "sync/atomic"
+
+// swapHandler wraps another handler that may be swapped out
+// dynamically at runtime in a thread-safe fashion.
+type swapHandler struct {
+	handler atomic.Value
+}
+
+func (h *swapHandler) Log(r *Record) error {
+	return (*h.handler.Load().(*Handler)).Log(r)
+}
+
+func (h *swapHandler) Swap(newHandler Handler) {
+	h.handler.Store(&newHandler)
+}
+
+func (h *swapHandler) Get() Handler {
+	return *h.handler.Load().(*Handler)
+}

+ 261 - 0
log/logger.go

@@ -0,0 +1,261 @@
+package log
+
+import (
+	"fmt"
+	"os"
+	"time"
+
+	"github.com/go-stack/stack"
+)
+
+const timeKey = "t"
+const lvlKey = "lvl"
+const msgKey = "msg"
+const ctxKey = "ctx"
+const errorKey = "LOG15_ERROR"
+const skipLevel = 2
+
+type Lvl int
+
+const (
+	LvlCrit Lvl = iota
+	LvlError
+	LvlWarn
+	LvlInfo
+	LvlDebug
+	LvlTrace
+)
+
+// AlignedString returns a 5-character string containing the name of a Lvl.
+func (l Lvl) AlignedString() string {
+	switch l {
+	case LvlTrace:
+		return "TRACE"
+	case LvlDebug:
+		return "DEBUG"
+	case LvlInfo:
+		return "INFO "
+	case LvlWarn:
+		return "WARN "
+	case LvlError:
+		return "ERROR"
+	case LvlCrit:
+		return "CRIT "
+	default:
+		panic("bad level")
+	}
+}
+
+// Strings returns the name of a Lvl.
+func (l Lvl) String() string {
+	switch l {
+	case LvlTrace:
+		return "trce"
+	case LvlDebug:
+		return "dbug"
+	case LvlInfo:
+		return "info"
+	case LvlWarn:
+		return "warn"
+	case LvlError:
+		return "eror"
+	case LvlCrit:
+		return "crit"
+	default:
+		panic("bad level")
+	}
+}
+
+// LvlFromString returns the appropriate Lvl from a string name.
+// Useful for parsing command line args and configuration files.
+func LvlFromString(lvlString string) (Lvl, error) {
+	switch lvlString {
+	case "trace", "trce":
+		return LvlTrace, nil
+	case "debug", "dbug":
+		return LvlDebug, nil
+	case "info":
+		return LvlInfo, nil
+	case "warn":
+		return LvlWarn, nil
+	case "error", "eror":
+		return LvlError, nil
+	case "crit":
+		return LvlCrit, nil
+	default:
+		return LvlDebug, fmt.Errorf("unknown level: %v", lvlString)
+	}
+}
+
+// A Record is what a Logger asks its handler to write
+type Record struct {
+	Time     time.Time
+	Lvl      Lvl
+	Msg      string
+	Ctx      []interface{}
+	Call     stack.Call
+	KeyNames RecordKeyNames
+}
+
+// RecordKeyNames gets stored in a Record when the write function is executed.
+type RecordKeyNames struct {
+	Time string
+	Msg  string
+	Lvl  string
+	Ctx  string
+}
+
+// A Logger writes key/value pairs to a Handler
+type Logger interface {
+	// New returns a new Logger that has this logger's context plus the given context
+	New(ctx ...interface{}) Logger
+
+	// GetHandler gets the handler associated with the logger.
+	GetHandler() Handler
+
+	// SetHandler updates the logger to write records to the specified handler.
+	SetHandler(h Handler)
+
+	// Log a message at the given level with context key/value pairs
+	Trace(msg string, ctx ...interface{})
+	Debug(msg string, ctx ...interface{})
+	Info(msg string, ctx ...interface{})
+	Warn(msg string, ctx ...interface{})
+	Error(msg string, ctx ...interface{})
+	Crit(msg string, ctx ...interface{})
+}
+
+type logger struct {
+	ctx []interface{}
+	h   *swapHandler
+}
+
+func (l *logger) write(msg string, lvl Lvl, ctx []interface{}, skip int) {
+	l.h.Log(&Record{
+		Time: time.Now(),
+		Lvl:  lvl,
+		Msg:  msg,
+		Ctx:  newContext(l.ctx, ctx),
+		Call: stack.Caller(skip),
+		KeyNames: RecordKeyNames{
+			Time: timeKey,
+			Msg:  msgKey,
+			Lvl:  lvlKey,
+			Ctx:  ctxKey,
+		},
+	})
+}
+
+func (l *logger) New(ctx ...interface{}) Logger {
+	child := &logger{newContext(l.ctx, ctx), new(swapHandler)}
+	child.SetHandler(l.h)
+	return child
+}
+
+func newContext(prefix []interface{}, suffix []interface{}) []interface{} {
+	normalizedSuffix := normalize(suffix)
+	newCtx := make([]interface{}, len(prefix)+len(normalizedSuffix))
+	n := copy(newCtx, prefix)
+	copy(newCtx[n:], normalizedSuffix)
+	return newCtx
+}
+
+func (l *logger) Trace(msg string, ctx ...interface{}) {
+	l.write(msg, LvlTrace, ctx, skipLevel)
+}
+
+func (l *logger) Debug(msg string, ctx ...interface{}) {
+	l.write(msg, LvlDebug, ctx, skipLevel)
+}
+
+func (l *logger) Info(msg string, ctx ...interface{}) {
+	l.write(msg, LvlInfo, ctx, skipLevel)
+}
+
+func (l *logger) Warn(msg string, ctx ...interface{}) {
+	l.write(msg, LvlWarn, ctx, skipLevel)
+}
+
+func (l *logger) Error(msg string, ctx ...interface{}) {
+	l.write(msg, LvlError, ctx, skipLevel)
+}
+
+func (l *logger) Crit(msg string, ctx ...interface{}) {
+	l.write(msg, LvlCrit, ctx, skipLevel)
+	os.Exit(1)
+}
+
+func (l *logger) GetHandler() Handler {
+	return l.h.Get()
+}
+
+func (l *logger) SetHandler(h Handler) {
+	l.h.Swap(h)
+}
+
+func normalize(ctx []interface{}) []interface{} {
+	// if the caller passed a Ctx object, then expand it
+	if len(ctx) == 1 {
+		if ctxMap, ok := ctx[0].(Ctx); ok {
+			ctx = ctxMap.toArray()
+		}
+	}
+
+	// ctx needs to be even because it's a series of key/value pairs
+	// no one wants to check for errors on logging functions,
+	// so instead of erroring on bad input, we'll just make sure
+	// that things are the right length and users can fix bugs
+	// when they see the output looks wrong
+	if len(ctx)%2 != 0 {
+		ctx = append(ctx, nil, errorKey, "Normalized odd number of arguments by adding nil")
+	}
+
+	return ctx
+}
+
+// Lazy allows you to defer calculation of a logged value that is expensive
+// to compute until it is certain that it must be evaluated with the given filters.
+//
+// Lazy may also be used in conjunction with a Logger's New() function
+// to generate a child logger which always reports the current value of changing
+// state.
+//
+// You may wrap any function which takes no arguments to Lazy. It may return any
+// number of values of any type.
+type Lazy struct {
+	Fn interface{}
+}
+
+// Ctx is a map of key/value pairs to pass as context to a log function
+// Use this only if you really need greater safety around the arguments you pass
+// to the logging functions.
+type Ctx map[string]interface{}
+
+func (c Ctx) toArray() []interface{} {
+	arr := make([]interface{}, len(c)*2)
+
+	i := 0
+	for k, v := range c {
+		arr[i] = k
+		arr[i+1] = v
+		i += 2
+	}
+
+	return arr
+}
+
+func NewFileLvlHandler(logPath string, maxBytesSize uint, level string) Handler {
+	rfh, err := RotatingFileHandler(
+		logPath,
+		maxBytesSize,
+		LogfmtFormat(),
+	)
+	if err != nil {
+		panic(err)
+	}
+	logLevel, err := LvlFromString(level)
+	if err != nil {
+		panic(err)
+	}
+	return LvlFilterHandler(logLevel, rfh)
+}

+ 70 - 0
log/root.go

@@ -0,0 +1,70 @@
+package log
+
+import (
+	"os"
+)
+
+var (
+	root          = &logger{[]interface{}{}, new(swapHandler)}
+	StdoutHandler = StreamHandler(os.Stdout, LogfmtFormat())
+	StderrHandler = StreamHandler(os.Stderr, LogfmtFormat())
+)
+
+func init() {
+	root.SetHandler(DiscardHandler())
+}
+
+// New returns a new logger with the given context.
+// New is a convenient alias for Root().New
+func New(ctx ...interface{}) Logger {
+	return root.New(ctx...)
+}
+
+// Root returns the root logger
+func Root() Logger {
+	return root
+}
+
+// The following functions bypass the exported logger methods (logger.Debug,
+// etc.) to keep the call depth the same for all paths to logger.write so
+// runtime.Caller(2) always refers to the call site in client code.
+
+// Trace is a convenient alias for Root().Trace
+func Trace(msg string, ctx ...interface{}) {
+	root.write(msg, LvlTrace, ctx, skipLevel)
+}
+
+// Debug is a convenient alias for Root().Debug
+func Debug(msg string, ctx ...interface{}) {
+	root.write(msg, LvlDebug, ctx, skipLevel)
+}
+
+// Info is a convenient alias for Root().Info
+func Info(msg string, ctx ...interface{}) {
+	root.write(msg, LvlInfo, ctx, skipLevel)
+}
+
+// Warn is a convenient alias for Root().Warn
+func Warn(msg string, ctx ...interface{}) {
+	root.write(msg, LvlWarn, ctx, skipLevel)
+}
+
+// Error is a convenient alias for Root().Error
+func Error(msg string, ctx ...interface{}) {
+	root.write(msg, LvlError, ctx, skipLevel)
+}
+
+// Crit is a convenient alias for Root().Crit
+func Crit(msg string, ctx ...interface{}) {
+	root.write(msg, LvlCrit, ctx, skipLevel)
+	os.Exit(1)
+}
+
+// Output is a convenient alias for write, allowing for the modification of
+// the calldepth (number of stack frames to skip).
+// calldepth influences the reported line number of the log message.
+// A calldepth of zero reports the immediate caller of Output.
+// Non-zero calldepth skips as many stack frames.
+func Output(msg string, lvl Lvl, calldepth int, ctx ...interface{}) {
+	root.write(msg, lvl, ctx, calldepth+skipLevel)
+}

+ 57 - 0
log/syslog.go

@@ -0,0 +1,57 @@
+// +build !windows,!plan9
+
+package log
+
+import (
+	"log/syslog"
+	"strings"
+)
+
+// SyslogHandler opens a connection to the system syslog daemon by calling
+// syslog.New and writes all records to it.
+func SyslogHandler(priority syslog.Priority, tag string, fmtr Format) (Handler, error) {
+	wr, err := syslog.New(priority, tag)
+	return sharedSyslog(fmtr, wr, err)
+}
+
+// SyslogNetHandler opens a connection to a log daemon over the network and writes
+// all log records to it.
+func SyslogNetHandler(net, addr string, priority syslog.Priority, tag string, fmtr Format) (Handler, error) {
+	wr, err := syslog.Dial(net, addr, priority, tag)
+	return sharedSyslog(fmtr, wr, err)
+}
+
+func sharedSyslog(fmtr Format, sysWr *syslog.Writer, err error) (Handler, error) {
+	if err != nil {
+		return nil, err
+	}
+	h := FuncHandler(func(r *Record) error {
+		var syslogFn = sysWr.Info
+		switch r.Lvl {
+		case LvlCrit:
+			syslogFn = sysWr.Crit
+		case LvlError:
+			syslogFn = sysWr.Err
+		case LvlWarn:
+			syslogFn = sysWr.Warning
+		case LvlInfo:
+			syslogFn = sysWr.Info
+		case LvlDebug:
+			syslogFn = sysWr.Debug
+		case LvlTrace:
+			syslogFn = func(m string) error { return nil } // There's no syslog level for trace
+		}
+
+		s := strings.TrimSpace(string(fmtr.Format(r)))
+		return syslogFn(s)
+	})
+	return LazyHandler(&closingHandler{sysWr, h}), nil
+}
+
+func (m muster) SyslogHandler(priority syslog.Priority, tag string, fmtr Format) Handler {
+	return must(SyslogHandler(priority, tag, fmtr))
+}
+
+func (m muster) SyslogNetHandler(net, addr string, priority syslog.Priority, tag string, fmtr Format) Handler {
+	return must(SyslogNetHandler(net, addr, priority, tag, fmtr))
+}

+ 172 - 0
p2p/config.go

@@ -0,0 +1,172 @@
+package p2p
+
+import (
+    "blockchain-go/common/mclock"
+    "blockchain-go/log"
+    "crypto/ecdsa"
+    "errors"
+    "net"
+    "sync"
+    "time"
+)
+
+const (
+    defaultDialTimeout = 15 * time.Second
+
+    // This is the fairness knob for the discovery mixer. When looking for peers, we'll
+    // wait this long for a single source of candidates before moving on and trying other
+    // sources.
+    discmixTimeout = 5 * time.Second
+
+    // Connectivity defaults.
+    defaultMaxPendingPeers = 50
+    defaultDialRatio       = 3
+
+    // This time limits inbound connection attempts per source IP.
+    inboundThrottleTime = 30 * time.Second
+
+    // Maximum time allowed for reading a complete message.
+    // This is effectively the amount of time a connection can be idle.
+    frameReadTimeout = 30 * time.Second
+
+    // Maximum amount of time allowed for writing a complete message.
+    frameWriteTimeout = 20 * time.Second
+
+    // Maximum time to wait before stop the p2p server
+    stopTimeout = 5 * time.Second
+)
+
+var errServerStopped = errors.New("server stopped")
+
+// Config holds Server options.
+type Config struct {
+    // This field must be set to a valid secp256k1 private key.
+    PrivateKey *ecdsa.PrivateKey `toml:"-"`
+
+    // MaxPeers is the maximum number of peers that can be
+    // connected. It must be greater than zero.
+    MaxPeers int
+
+    // MaxPendingPeers is the maximum number of peers that can be pending in the
+    // handshake phase, counted separately for inbound and outbound connections.
+    // Zero defaults to preset values.
+    MaxPendingPeers int `toml:",omitempty"`
+
+    // DialRatio controls the ratio of inbound to dialed connections.
+    // Example: a DialRatio of 2 allows 1/2 of connections to be dialed.
+    // Setting DialRatio to zero defaults it to 3.
+    DialRatio int `toml:",omitempty"`
+
+    // NoDiscovery can be used to disable the peer discovery mechanism.
+    // Disabling is useful for protocol debugging (manual topology).
+    NoDiscovery bool
+
+    // DiscoveryV5 specifies whether the new topic-discovery based V5 discovery
+    // protocol should be started or not.
+    DiscoveryV5 bool `toml:",omitempty"`
+
+    // Name sets the node name of this server.
+    // Use common.MakeName to create a name that follows existing conventions.
+    Name string `toml:"-"`
+
+    // BootstrapNodes are used to establish connectivity
+    // with the rest of the network.
+    //BootstrapNodes []*enode.Node
+
+    // BootstrapNodesV5 are used to establish connectivity
+    // with the rest of the network using the V5 discovery
+    // protocol.
+    //BootstrapNodesV5 []*enode.Node `toml:",omitempty"`
+
+    // Static nodes are used as pre-configured connections which are always
+    // maintained and re-connected on disconnects.
+    //StaticNodes []*enode.Node
+
+    // Trusted nodes are used as pre-configured connections which are always
+    // allowed to connect, even above the peer limit.
+    //TrustedNodes []*enode.Node
+
+    // Connectivity can be restricted to certain IP networks.
+    // If this option is set to a non-nil value, only hosts which match one of the
+    // IP networks contained in the list are considered.
+    //NetRestrict *netutil.Netlist `toml:",omitempty"`
+
+    // NodeDatabase is the path to the database containing the previously seen
+    // live nodes in the network.
+    NodeDatabase string `toml:",omitempty"`
+
+    // Protocols should contain the protocols supported
+    // by the server. Matching protocols are launched for
+    // each peer.
+    //Protocols []Protocol `toml:"-"`
+
+    // If ListenAddr is set to a non-nil address, the server
+    // will listen for incoming connections.
+    //
+    // If the port is zero, the operating system will pick a port. The
+    // ListenAddr field will be updated with the actual address when
+    // the server is started.
+    ListenAddr string
+
+    // If set to a non-nil value, the given NAT port mapper
+    // is used to make the listening port available to the
+    // Internet.
+    //NAT nat.Interface `toml:",omitempty"`
+
+    // If Dialer is set to a non-nil value, the given Dialer
+    // is used to dial outbound peer connections.
+    //Dialer NodeDialer `toml:"-"`
+
+    // If NoDial is true, the server will not dial any peers.
+    NoDial bool `toml:",omitempty"`
+
+    // If EnableMsgEvents is set then the server will emit PeerEvents
+    // whenever a message is sent to or received from a peer
+    EnableMsgEvents bool
+
+    // Logger is a custom logger to use with the p2p.Server.
+    Logger log.Logger `toml:",omitempty"`
+
+    clock mclock.Clock
+}
+
+// Server manages all peer connections.
+type Server struct {
+    // Config fields may not be modified while the server is running.
+    Config
+
+    // Hooks for testing. These are useful because we can inhibit
+    // the whole protocol stack.
+    //newTransport func(net.Conn, *ecdsa.PublicKey) transport
+    //newPeerHook  func(*Peer)
+    listenFunc func(network, addr string) (net.Listener, error)
+
+    lock    sync.Mutex // protects running
+    running bool
+
+    listener net.Listener
+    //ourHandshake *protoHandshake
+    loopWG   sync.WaitGroup // loop, listenLoop
+    //peerFeed event.Feed
+    log      log.Logger
+
+    //nodedb    *enode.DB
+    //localnode *enode.LocalNode
+    //ntab      *discover.UDPv4
+    //DiscV5    *discover.UDPv5
+    //discmix   *enode.FairMix
+    //dialsched *dialScheduler
+
+    // Channels into the run loop.
+    quit                    chan struct{}
+    //addtrusted              chan *enode.Node
+    //removetrusted           chan *enode.Node
+    //peerOp                  chan peerOpFunc
+    peerOpDone              chan struct{}
+    //delpeer                 chan peerDrop
+    //checkpointPostHandshake chan *conn
+    //checkpointAddPeer       chan *conn
+
+    // State of run loop and listenLoop.
+    //inboundHistory expHeap
+}

+ 1 - 0
p2p/server.go

@@ -0,0 +1 @@
+package p2p