diff --git a/common/big.go b/common/big.go index 4ce87ee0c6..5e95224ef0 100644 --- a/common/big.go +++ b/common/big.go @@ -116,14 +116,19 @@ func FirstBitSet(v *big.Int) int { // // Returns the bytes of a big integer with the size specified by **base** // Attempts to pad the byte array with zeros. +// +// Note that input arg **num** is expected to be non-nil; +// nil argument will result in runtime panic. func BigToBytes(num *big.Int, base int) []byte { - ret := make([]byte, base/8) + bytes := num.Bytes() + blen := len(bytes) + bpb := base / 8 - if len(num.Bytes()) > base/8 { - return num.Bytes() + if blen > bpb { + return bytes } - - return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...) + padBuf := make([]byte, bpb) + return append(padBuf[:bpb-blen], bytes...) } // Big copy diff --git a/common/bytes.go b/common/bytes.go index b9fb3b2da6..68ccbd37d9 100644 --- a/common/bytes.go +++ b/common/bytes.go @@ -14,7 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package common contains various helper functions. package common import ( @@ -61,60 +60,29 @@ func NumberToBytes(num interface{}, bits int) []byte { return buf.Bytes()[buf.Len()-(bits/8):] } -// Bytes to number -// -// Attempts to cast a byte slice to a unsigned integer +// Converts byte slice to a unsigned integer. Bytes are +// interpreted as big-endian image of unsigned 64bit integer. +// Slices less than 8 bytes are left padded before conversion; +// For slices larger than 8 bytes the trailing bytes are ignored. func BytesToNumber(b []byte) uint64 { - var number uint64 + var data = LeftPadBytes(b, 8) - // Make sure the buffer is 64bits - data := make([]byte, 8) - data = append(data[:len(b)], b...) + var n uint64 + n |= uint64(data[0]) << 56 + n |= uint64(data[1]) << 48 + n |= uint64(data[2]) << 40 + n |= uint64(data[3]) << 32 + n |= uint64(data[4]) << 24 + n |= uint64(data[5]) << 16 + n |= uint64(data[6]) << 8 + n |= uint64(data[7]) - buf := bytes.NewReader(data) - err := binary.Read(buf, binary.BigEndian, &number) - if err != nil { - fmt.Println("BytesToNumber failed:", err) - } - - return number + return n } -// Read variable int -// -// Read a variable length number in big endian byte order -func ReadVarInt(buff []byte) (ret uint64) { - switch l := len(buff); { - case l > 4: - d := LeftPadBytes(buff, 8) - binary.Read(bytes.NewReader(d), binary.BigEndian, &ret) - case l > 2: - var num uint32 - d := LeftPadBytes(buff, 4) - binary.Read(bytes.NewReader(d), binary.BigEndian, &num) - ret = uint64(num) - case l > 1: - var num uint16 - d := LeftPadBytes(buff, 2) - binary.Read(bytes.NewReader(d), binary.BigEndian, &num) - ret = uint64(num) - default: - var num uint8 - binary.Read(bytes.NewReader(buff), binary.BigEndian, &num) - ret = uint64(num) - } - - return -} - -// Copy bytes -// // Returns an exact copy of the provided bytes func CopyBytes(b []byte) (copiedBytes []byte) { - copiedBytes = make([]byte, len(b)) - copy(copiedBytes, b) - - return + return append([]byte{}, b...) } func HasHexPrefix(str string) bool { @@ -137,7 +105,7 @@ func Hex2Bytes(str string) []byte { return h } -func Hex2BytesFixed(str string, flen int) []byte { +func HexToBytesFixed(str string, flen int) []byte { h, _ := hex.DecodeString(str) if len(h) == flen { return h diff --git a/common/bytes_test.go b/common/bytes_test.go index 2e52084777..49b4796a56 100644 --- a/common/bytes_test.go +++ b/common/bytes_test.go @@ -39,47 +39,59 @@ func (s *BytesSuite) TestNumberToBytes(c *checker.C) { } func (s *BytesSuite) TestBytesToNumber(c *checker.C) { - datasmall := []byte{0xe9, 0x38, 0xe9, 0x38} - datalarge := []byte{0xe9, 0x38, 0xe9, 0x38, 0xe9, 0x38, 0xe9, 0x38} + data := [][]byte{ + // check for zero-len + []byte{}, + // check for len < 8 + []byte{0xfe}, + []byte{0xca, 0xfe}, + []byte{0xca, 0xfe, 0xba, 0xbe}, + // check case len < 8 + []byte{0x7f, 0x6f, 0x5f, 0x4f, 0x3f, 0x2f, 0x1f, 0x0f}, + // check case len = 8 + []byte{0x7f, 0x6f, 0x5f, 0x4f, 0x3f, 0x2f, 0x1f, 0x0f, 0xba, 0xdc, 0x0d}, + } + expected := []uint64{ + 0x0, + 0xfe, + 0xcafe, + 0xcafebabe, + 0x7f6f5f4f3f2f1f0f, + 0x7f6f5f4f3f2f1f0f, + } - var expsmall uint64 = 0xe938e938 - var explarge uint64 = 0x0 + // assert-test-invariants: + c.Assert(len(data[0]), checker.Equals, 0) + c.Assert(len(data[1]), checker.Equals, 1) + c.Assert(len(data[2]), checker.Equals, 2) + c.Assert(len(data[3]), checker.Equals, 4) + c.Assert(len(data[4]), checker.Equals, 8) + c.Assert(len(data[5]), checker.Equals, 11) - ressmall := BytesToNumber(datasmall) - reslarge := BytesToNumber(datalarge) + c.Assert(len(expected), checker.Equals, len(data)) - c.Assert(ressmall, checker.Equals, expsmall) - c.Assert(reslarge, checker.Equals, explarge) - -} - -func (s *BytesSuite) TestReadVarInt(c *checker.C) { - data8 := []byte{1, 2, 3, 4, 5, 6, 7, 8} - data4 := []byte{1, 2, 3, 4} - data2 := []byte{1, 2} - data1 := []byte{1} - - exp8 := uint64(72623859790382856) - exp4 := uint64(16909060) - exp2 := uint64(258) - exp1 := uint64(1) - - res8 := ReadVarInt(data8) - res4 := ReadVarInt(data4) - res2 := ReadVarInt(data2) - res1 := ReadVarInt(data1) - - c.Assert(res8, checker.Equals, exp8) - c.Assert(res4, checker.Equals, exp4) - c.Assert(res2, checker.Equals, exp2) - c.Assert(res1, checker.Equals, exp1) + for i := 0; i < len(data); i++ { + have := BytesToNumber(data[i]) + c.Assert(have, checker.Equals, expected[i]) + } } func (s *BytesSuite) TestCopyBytes(c *checker.C) { - data1 := []byte{1, 2, 3, 4} - exp1 := []byte{1, 2, 3, 4} - res1 := CopyBytes(data1) - c.Assert(res1, checker.DeepEquals, exp1) + data := [][]byte{ + []byte{0x00, 0x7f, 0x80, 0xff}, // interesting bytes + []byte{}, // empty case + } + + // test + for i := 0; i < len(data); i++ { + have := CopyBytes(data[i]) + if data[i] != nil { + // make sure we're not just returning the input arg + c.Assert(&have, checker.Not(checker.Equals), &data[i]) + } + // verify deep copy + c.Assert(have, checker.DeepEquals, data[i]) + } } func (s *BytesSuite) TestIsHex(c *checker.C) { diff --git a/common/pkgdoc.go b/common/pkgdoc.go new file mode 100644 index 0000000000..72d08f8159 --- /dev/null +++ b/common/pkgdoc.go @@ -0,0 +1,18 @@ +// 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 . + +// Package common contains various helper functions. +package common