From 1af7abd6be3fcb7afbe429063b032dc20ab15c12 Mon Sep 17 00:00:00 2001
From: Silas Davis <silas@monax.io>
Date: Fri, 2 Mar 2018 17:23:45 +0000
Subject: [PATCH] Fix issue with SIGNEXTEND and refactor arithmetic Our
 SIGNEXTEND was broken on positive numbers because for these numbers it
 `Add`ed the sign extension mask rather than `And`ing it.

I took the opportunity to tidy up the arithmetical opcodes and add some
test.

Signed-off-by: Silas Davis <silas@monax.io>
---
 binary/integer.go              |  45 +++++++-
 binary/integer_test.go         | 158 ++++++++++++++++++++++++++
 binary/word256.go              |   5 +-
 binary/word256_test.go         |   4 +
 execution/evm/common.go        |  40 -------
 execution/evm/stack.go         |  20 ++++
 execution/evm/vm.go            | 202 ++++++++++++---------------------
 execution/execution.go         |  18 +--
 logging/config/filter_test.go  |  16 +++
 logging/lifecycle/lifecycle.go |   4 +-
 10 files changed, 329 insertions(+), 183 deletions(-)
 delete mode 100644 execution/evm/common.go

diff --git a/binary/integer.go b/binary/integer.go
index f8651484..a00c0705 100644
--- a/binary/integer.go
+++ b/binary/integer.go
@@ -17,10 +17,14 @@ package binary
 import (
 	"encoding/binary"
 	"math"
+	"math/big"
 	"sort"
 )
 
-const Uint64TopBitMask = 1 << 63
+var big1 = big.NewInt(1)
+var tt256 = new(big.Int).Lsh(big1, 256)
+var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big1, 256), big1)
+var tt255 = new(big.Int).Lsh(big1, 255)
 
 // Sort for []uint64
 
@@ -75,3 +79,42 @@ func GetInt64BE(src []byte) int64 {
 func IsUint64SumOverflow(a, b uint64) bool {
 	return math.MaxUint64-a < b
 }
+
+//
+
+// Converts a possibly negative big int x into a positive big int encoding a twos complement representation of x
+// truncated to 32 bytes
+func U256(x *big.Int) *big.Int {
+	// Note that the And operation induces big.Int to hold a positive representation of a negative number
+	return new(big.Int).And(x, tt256m1)
+}
+
+// Interprets a positive big.Int as a 256-bit two's complement signed integer
+func S256(x *big.Int) *big.Int {
+	// Sign bit not set, value is its positive self
+	if x.Cmp(tt255) < 0 {
+		return x
+	} else {
+		// negative value is represented
+		return new(big.Int).Sub(x, tt256)
+	}
+}
+
+// Treats the positive big int x as if it contains an embedded a back + 1 byte signed integer in its least significant
+// bits and extends that sign
+func SignExtend(back uint64, x *big.Int) *big.Int {
+	// we assume x contains a signed integer of back + 1 bytes width
+	// most significant bit of the back'th byte,
+	signBit := back*8 + 7
+	// single bit set at sign bit position
+	mask := new(big.Int).Lsh(big1, uint(signBit))
+	// all bits below sign bit set to 1 all above (including sign bit) set to 0
+	mask.Sub(mask, big1)
+	if x.Bit(int(signBit)) == 1 {
+		// Number represented is negative - set all bits above sign bit (including sign bit)
+		return x.Or(x, mask.Not(mask))
+	} else {
+		// Number represented is positive - clear all bits above sign bit (including sign bit)
+		return x.And(x, mask)
+	}
+}
diff --git a/binary/integer_test.go b/binary/integer_test.go
index e530c5a7..c0c1533f 100644
--- a/binary/integer_test.go
+++ b/binary/integer_test.go
@@ -2,9 +2,16 @@ package binary
 
 import (
 	"math"
+	"math/big"
 	"testing"
 
+	"strconv"
+	"strings"
+
+	"fmt"
+
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func TestIsUint64SumOverflow(t *testing.T) {
@@ -17,3 +24,154 @@ func TestIsUint64SumOverflow(t *testing.T) {
 	assert.True(t, IsUint64SumOverflow(a+b, 1))
 	assert.True(t, IsUint64SumOverflow(a+1, b+1))
 }
+
+func zero() *big.Int {
+	return new(big.Int)
+}
+
+var big2E255 = zero().Lsh(big1, 255)
+var big2E256 = zero().Lsh(big1, 256)
+var big2E257 = zero().Lsh(big1, 257)
+
+func TestU256(t *testing.T) {
+	expected := big2E255
+	encoded := U256(expected)
+	assertBigIntEqual(t, expected, encoded, "Top bit set big int is fixed point")
+
+	expected = zero()
+	encoded = U256(big2E256)
+	assertBigIntEqual(t, expected, encoded, "Ceiling bit is exact overflow")
+
+	expected = zero().Sub(big2E256, big1)
+	encoded = U256(expected)
+	assertBigIntEqual(t, expected, encoded, "Max unsigned big int is fixed point")
+
+	expected = big1
+	encoded = U256(zero().Add(big2E256, big1))
+	assertBigIntEqual(t, expected, encoded, "Overflow by one")
+
+	expected = big2E255
+	encoded = U256(zero().Add(big2E256, big2E255))
+	assertBigIntEqual(t, expected, encoded, "Overflow by doubling")
+
+	negative := big.NewInt(-234)
+	assert.Equal(t, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16",
+		fmt.Sprintf("%X", U256(negative).Bytes()), "byte representation is twos complement")
+
+	expected, ok := zero().SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16", 16)
+	require.True(t, ok)
+	assertBigIntEqual(t, expected, U256(negative), "Bytes representation should be twos complement")
+
+	expected = zero()
+	encoded = U256(zero().Neg(big2E256))
+	assertBigIntEqual(t, expected, encoded, "Floor bit is overflow")
+
+	expected = big2E255
+	encoded = zero().Neg(big2E255)
+	encoded = U256(encoded)
+	assertBigIntEqual(t, expected, encoded, "2**255 is Self complement")
+
+	expected = zero().Add(big2E255, big1)
+	encoded = zero().Neg(big2E255)
+	encoded = encoded.Add(encoded, big1)
+	encoded = U256(encoded)
+	assertBigIntEqual(t, expected, encoded, "")
+}
+
+func TestS256(t *testing.T) {
+	expected := zero().Neg(big2E255)
+	signed := S256(big2E255)
+	assertBigIntEqual(t, expected, signed, "Should be negative")
+
+	expected = zero().Sub(big2E255, big1)
+	signed = S256(expected)
+	assertBigIntEqual(t, expected, signed, "Maximum twos complement positive is fixed point")
+
+	expected = zero()
+	signed = S256(expected)
+	assertBigIntEqual(t, expected, signed, "Twos complement of zero is fixed poount")
+
+	// Technically undefined but let's not let that stop us
+	expected = zero().Sub(big2E257, big2E256)
+	signed = S256(big2E257)
+	assertBigIntEqual(t, expected, signed, "Out of twos complement bounds")
+}
+
+func TestSignExtend(t *testing.T) {
+	assertSignExtend(t, 16, 0,
+		"0000 0000 1001 0000",
+		"1111 1111 1001 0000")
+
+	assertSignExtend(t, 16, 1,
+		"1001 0000",
+		"1001 0000")
+
+	assertSignExtend(t, 32, 2,
+		"0000 0000 1000 0000 1101 0011 1001 0000",
+		"1111 1111 1000 0000 1101 0011 1001 0000")
+
+	assertSignExtend(t, 32, 2,
+		"0000 0000 0000 0000 1101 0011 1001 0000",
+		"0000 0000 0000 0000 1101 0011 1001 0000")
+
+	// Here we have a stray bit set in the 4th most significant byte that gets wiped out
+	assertSignExtend(t, 32, 2,
+		"0001 0000 0000 0000 1101 0011 1001 0000",
+		"0000 0000 0000 0000 1101 0011 1001 0000")
+	assertSignExtend(t, 32, 2,
+		"0001 0000 1000 0000 1101 0011 1001 0000",
+		"1111 1111 1000 0000 1101 0011 1001 0000")
+
+	assertSignExtend(t, 32, 3,
+		"0001 0000 1000 0000 1101 0011 1001 0000",
+		"0001 0000 1000 0000 1101 0011 1001 0000")
+
+	assertSignExtend(t, 32, 3,
+		"1001 0000 1000 0000 1101 0011 1001 0000",
+		"1001 0000 1000 0000 1101 0011 1001 0000")
+
+	assertSignExtend(t, 64, 3,
+		"0000 0000 0000 0000 0000 0000 0000 0000 1001 0000 1000 0000 1101 0011 1001 0000",
+		"1111 1111 1111 1111 1111 1111 1111 1111 1001 0000 1000 0000 1101 0011 1001 0000")
+
+	assertSignExtend(t, 64, 3,
+		"0000 0000 0000 0000 0000 0000 0000 0000 0001 0000 1000 0000 1101 0011 1001 0000",
+		"0000 0000 0000 0000 0000 0000 0000 0000 0001 0000 1000 0000 1101 0011 1001 0000")
+}
+
+func assertSignExtend(t *testing.T, bitSize int, bytesBack uint64, inputString, expectedString string) bool {
+	input := intFromString(t, bitSize, inputString)
+	expected := intFromString(t, bitSize, expectedString)
+	//actual := SignExtend(big.NewInt(bytesBack), big.NewInt(int64(input)))
+	actual := SignExtend(bytesBack, big.NewInt(int64(input)))
+	var ret bool
+	switch bitSize {
+	case 8:
+		ret = assert.Equal(t, uint8(expected), uint8(actual.Int64()))
+	case 16:
+		ret = assert.Equal(t, uint16(expected), uint16(actual.Int64()))
+	case 32:
+		ret = assert.Equal(t, uint32(expected), uint32(actual.Int64()))
+	case 64:
+		ret = assert.Equal(t, uint64(expected), uint64(actual.Int64()))
+	default:
+		t.Fatalf("Cannot test SignExtend for non-Go-native bit size %v", bitSize)
+		return false
+	}
+	if !ret {
+
+	}
+	return ret
+}
+
+func assertBigIntEqual(t *testing.T, expected, actual *big.Int, messages ...string) bool {
+	return assert.True(t, expected.Cmp(actual) == 0, fmt.Sprintf("%s - not equal:\n%v (expected)\n%v (actual)",
+		strings.Join(messages, " "), expected, actual))
+}
+
+func intFromString(t *testing.T, bitSize int, binStrings ...string) uint64 {
+	binaryString := strings.Replace(strings.Join(binStrings, ""), " ", "", -1)
+	i, err := strconv.ParseUint(binaryString, 2, bitSize)
+	require.NoError(t, err)
+	return i
+}
diff --git a/binary/word256.go b/binary/word256.go
index 6d11fe9a..02a90581 100644
--- a/binary/word256.go
+++ b/binary/word256.go
@@ -16,16 +16,19 @@ package binary
 
 import (
 	"bytes"
+	"math/big"
 	"sort"
 )
 
 var (
 	Zero256 = Word256{}
-	One256  = Word256{1}
+	One256  = LeftPadWord256([]byte{1})
 )
 
 const Word256Length = 32
 
+var BigWord256Length = big.NewInt(Word256Length)
+
 var trimCutSet = string([]byte{0})
 
 type Word256 [Word256Length]byte
diff --git a/binary/word256_test.go b/binary/word256_test.go
index 055d3910..78aaeb59 100644
--- a/binary/word256_test.go
+++ b/binary/word256_test.go
@@ -37,3 +37,7 @@ func TestLeftPadWord256(t *testing.T) {
 		},
 		LeftPadWord256([]byte{1, 2, 3}))
 }
+
+func TestOne256(t *testing.T) {
+	assert.Equal(t, Int64ToWord256(1), One256)
+}
diff --git a/execution/evm/common.go b/execution/evm/common.go
deleted file mode 100644
index e8fb7444..00000000
--- a/execution/evm/common.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2017 Monax Industries Limited
-//
-// 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.
-
-package evm
-
-import (
-	"math/big"
-)
-
-// To256
-//
-// "cast" the big int to a 256 big int (i.e., limit to)
-var tt256 = new(big.Int).Lsh(big.NewInt(1), 256)
-var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
-var tt255 = new(big.Int).Lsh(big.NewInt(1), 255)
-
-func U256(x *big.Int) *big.Int {
-	x.And(x, tt256m1)
-	return x
-}
-
-func S256(x *big.Int) *big.Int {
-	if x.Cmp(tt255) < 0 {
-		return x
-	} else {
-		// We don't want to modify x, ever
-		return new(big.Int).Sub(x, tt256)
-	}
-}
diff --git a/execution/evm/stack.go b/execution/evm/stack.go
index 0d8a8f3f..2db80183 100644
--- a/execution/evm/stack.go
+++ b/execution/evm/stack.go
@@ -17,6 +17,8 @@ package evm
 import (
 	"fmt"
 
+	"math/big"
+
 	. "github.com/hyperledger/burrow/binary"
 )
 
@@ -78,6 +80,15 @@ func (st *Stack) PushU64(i uint64) {
 	st.Push(Uint64ToWord256(i))
 }
 
+// Pushes the bigInt as a Word256 encoding negative values in 32-byte twos complement and returns the encoded result
+func (st *Stack) PushBigInt(bigInt *big.Int) Word256 {
+	word := LeftPadWord256(U256(bigInt).Bytes())
+	st.Push(word)
+	return word
+}
+
+// Pops
+
 func (st *Stack) Pop() Word256 {
 	st.useGas(GasStackOp)
 	if st.ptr == 0 {
@@ -102,6 +113,15 @@ func (st *Stack) PopU64() uint64 {
 	return Uint64FromWord256(d)
 }
 
+func (st *Stack) PopBigIntSigned() *big.Int {
+	return S256(st.PopBigInt())
+}
+
+func (st *Stack) PopBigInt() *big.Int {
+	d := st.Pop()
+	return new(big.Int).SetBytes(d[:])
+}
+
 func (st *Stack) Len() int {
 	return st.ptr
 }
diff --git a/execution/evm/vm.go b/execution/evm/vm.go
index f20efce7..3513e5ac 100644
--- a/execution/evm/vm.go
+++ b/execution/evm/vm.go
@@ -18,7 +18,6 @@ import (
 	"bytes"
 	"errors"
 	"fmt"
-	"math/big"
 
 	acm "github.com/hyperledger/burrow/account"
 	. "github.com/hyperledger/burrow/binary"
@@ -220,202 +219,147 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 		switch op {
 
 		case ADD: // 0x01
-			x, y := stack.Pop(), stack.Pop()
-			xb := new(big.Int).SetBytes(x[:])
-			yb := new(big.Int).SetBytes(y[:])
-			sum := new(big.Int).Add(xb, yb)
-			res := LeftPadWord256(U256(sum).Bytes())
-			stack.Push(res)
-			vm.Debugf(" %v + %v = %v (%X)\n", xb, yb, sum, res)
+			x, y := stack.PopBigInt(), stack.PopBigInt()
+			sum := x.Add(x, y)
+			res := stack.PushBigInt(sum)
+			vm.Debugf(" %v + %v = %v (%X)\n", x, y, sum, res)
 
 		case MUL: // 0x02
-			x, y := stack.Pop(), stack.Pop()
-			xb := new(big.Int).SetBytes(x[:])
-			yb := new(big.Int).SetBytes(y[:])
-			prod := new(big.Int).Mul(xb, yb)
-			res := LeftPadWord256(U256(prod).Bytes())
-			stack.Push(res)
-			vm.Debugf(" %v * %v = %v (%X)\n", xb, yb, prod, res)
+			x, y := stack.PopBigInt(), stack.PopBigInt()
+			prod := x.Mul(x, y)
+			res := stack.PushBigInt(prod)
+			vm.Debugf(" %v * %v = %v (%X)\n", x, y, prod, res)
 
 		case SUB: // 0x03
-			x, y := stack.Pop(), stack.Pop()
-			xb := new(big.Int).SetBytes(x[:])
-			yb := new(big.Int).SetBytes(y[:])
-			diff := new(big.Int).Sub(xb, yb)
-			res := LeftPadWord256(U256(diff).Bytes())
-			stack.Push(res)
-			vm.Debugf(" %v - %v = %v (%X)\n", xb, yb, diff, res)
+			x, y := stack.PopBigInt(), stack.PopBigInt()
+			diff := x.Sub(x, y)
+			res := stack.PushBigInt(diff)
+			vm.Debugf(" %v - %v = %v (%X)\n", x, y, diff, res)
 
 		case DIV: // 0x04
-			x, y := stack.Pop(), stack.Pop()
-			if y.IsZero() {
+			x, y := stack.PopBigInt(), stack.PopBigInt()
+			if y.Sign() == 0 {
 				stack.Push(Zero256)
 				vm.Debugf(" %x / %x = %v\n", x, y, 0)
 			} else {
-				xb := new(big.Int).SetBytes(x[:])
-				yb := new(big.Int).SetBytes(y[:])
-				div := new(big.Int).Div(xb, yb)
-				res := LeftPadWord256(U256(div).Bytes())
-				stack.Push(res)
-				vm.Debugf(" %v / %v = %v (%X)\n", xb, yb, div, res)
+				div := x.Div(x, y)
+				res := stack.PushBigInt(div)
+				vm.Debugf(" %v / %v = %v (%X)\n", x, y, div, res)
 			}
 
 		case SDIV: // 0x05
-			x, y := stack.Pop(), stack.Pop()
-			if y.IsZero() {
+			x, y := stack.PopBigIntSigned(), stack.PopBigIntSigned()
+			if y.Sign() == 0 {
 				stack.Push(Zero256)
 				vm.Debugf(" %x / %x = %v\n", x, y, 0)
 			} else {
-				xb := S256(new(big.Int).SetBytes(x[:]))
-				yb := S256(new(big.Int).SetBytes(y[:]))
-				div := new(big.Int).Div(xb, yb)
-				res := LeftPadWord256(U256(div).Bytes())
-				stack.Push(res)
-				vm.Debugf(" %v / %v = %v (%X)\n", xb, yb, div, res)
+				div := x.Div(x, y)
+				res := stack.PushBigInt(div)
+				vm.Debugf(" %v / %v = %v (%X)\n", x, y, div, res)
 			}
 
 		case MOD: // 0x06
-			x, y := stack.Pop(), stack.Pop()
-			if y.IsZero() {
+			x, y := stack.PopBigInt(), stack.PopBigInt()
+			if y.Sign() == 0 {
 				stack.Push(Zero256)
 				vm.Debugf(" %v %% %v = %v\n", x, y, 0)
 			} else {
-				xb := new(big.Int).SetBytes(x[:])
-				yb := new(big.Int).SetBytes(y[:])
-				mod := new(big.Int).Mod(xb, yb)
-				res := LeftPadWord256(U256(mod).Bytes())
-				stack.Push(res)
-				vm.Debugf(" %v %% %v = %v (%X)\n", xb, yb, mod, res)
+				mod := x.Mod(x, y)
+				res := stack.PushBigInt(mod)
+				vm.Debugf(" %v %% %v = %v (%X)\n", x, y, mod, res)
 			}
 
 		case SMOD: // 0x07
-			x, y := stack.Pop(), stack.Pop()
-			if y.IsZero() {
+			x, y := stack.PopBigIntSigned(), stack.PopBigIntSigned()
+			if y.Sign() == 0 {
 				stack.Push(Zero256)
 				vm.Debugf(" %v %% %v = %v\n", x, y, 0)
 			} else {
-				xb := S256(new(big.Int).SetBytes(x[:]))
-				yb := S256(new(big.Int).SetBytes(y[:]))
-				mod := new(big.Int).Mod(xb, yb)
-				res := LeftPadWord256(U256(mod).Bytes())
-				stack.Push(res)
-				vm.Debugf(" %v %% %v = %v (%X)\n", xb, yb, mod, res)
+				mod := x.Mod(x, y)
+				res := stack.PushBigInt(mod)
+				vm.Debugf(" %v %% %v = %v (%X)\n", x, y, mod, res)
 			}
 
 		case ADDMOD: // 0x08
-			x, y, z := stack.Pop(), stack.Pop(), stack.Pop()
-			if z.IsZero() {
+			x, y, z := stack.PopBigInt(), stack.PopBigInt(), stack.PopBigInt()
+			if z.Sign() == 0 {
 				stack.Push(Zero256)
 				vm.Debugf(" %v %% %v = %v\n", x, y, 0)
 			} else {
-				xb := new(big.Int).SetBytes(x[:])
-				yb := new(big.Int).SetBytes(y[:])
-				zb := new(big.Int).SetBytes(z[:])
-				add := new(big.Int).Add(xb, yb)
-				mod := new(big.Int).Mod(add, zb)
-				res := LeftPadWord256(U256(mod).Bytes())
-				stack.Push(res)
-				vm.Debugf(" %v + %v %% %v = %v (%X)\n",
-					xb, yb, zb, mod, res)
+				add := x.Add(x, y)
+				mod := add.Mod(add, z)
+				res := stack.PushBigInt(mod)
+				vm.Debugf(" %v + %v %% %v = %v (%X)\n", x, y, z, mod, res)
 			}
 
 		case MULMOD: // 0x09
-			x, y, z := stack.Pop(), stack.Pop(), stack.Pop()
-			if z.IsZero() {
+			x, y, z := stack.PopBigInt(), stack.PopBigInt(), stack.PopBigInt()
+			if z.Sign() == 0 {
 				stack.Push(Zero256)
 				vm.Debugf(" %v %% %v = %v\n", x, y, 0)
 			} else {
-				xb := new(big.Int).SetBytes(x[:])
-				yb := new(big.Int).SetBytes(y[:])
-				zb := new(big.Int).SetBytes(z[:])
-				mul := new(big.Int).Mul(xb, yb)
-				mod := new(big.Int).Mod(mul, zb)
-				res := LeftPadWord256(U256(mod).Bytes())
-				stack.Push(res)
-				vm.Debugf(" %v * %v %% %v = %v (%X)\n",
-					xb, yb, zb, mod, res)
+				mul := x.Mul(x, y)
+				mod := mul.Mod(mul, z)
+				res := stack.PushBigInt(mod)
+				vm.Debugf(" %v * %v %% %v = %v (%X)\n", x, y, z, mod, res)
 			}
 
 		case EXP: // 0x0A
-			x, y := stack.Pop(), stack.Pop()
-			xb := new(big.Int).SetBytes(x[:])
-			yb := new(big.Int).SetBytes(y[:])
-			pow := new(big.Int).Exp(xb, yb, big.NewInt(0))
-			res := LeftPadWord256(U256(pow).Bytes())
-			stack.Push(res)
-			vm.Debugf(" %v ** %v = %v (%X)\n", xb, yb, pow, res)
+			x, y := stack.PopBigInt(), stack.PopBigInt()
+			pow := x.Exp(x, y, nil)
+			res := stack.PushBigInt(pow)
+			vm.Debugf(" %v ** %v = %v (%X)\n", x, y, pow, res)
 
 		case SIGNEXTEND: // 0x0B
-			back := stack.Pop()
-			backb := new(big.Int).SetBytes(back[:])
-			if backb.Cmp(big.NewInt(31)) < 0 {
-				bit := uint(backb.Uint64()*8 + 7)
-				num := stack.Pop()
-				numb := new(big.Int).SetBytes(num[:])
-				mask := new(big.Int).Lsh(big.NewInt(1), bit)
-				mask.Sub(mask, big.NewInt(1))
-				if numb.Bit(int(bit)) == 1 {
-					numb.Or(numb, mask.Not(mask))
-				} else {
-					numb.Add(numb, mask)
-				}
-				res := LeftPadWord256(U256(numb).Bytes())
-				vm.Debugf(" = %v (%X)", numb, res)
-				stack.Push(res)
+			back := stack.PopU64()
+			if back < Word256Length-1 {
+				stack.PushBigInt(SignExtend(back, stack.PopBigInt()))
 			}
 
 		case LT: // 0x10
-			x, y := stack.Pop(), stack.Pop()
-			xb := new(big.Int).SetBytes(x[:])
-			yb := new(big.Int).SetBytes(y[:])
-			if xb.Cmp(yb) < 0 {
-				stack.Push64(1)
-				vm.Debugf(" %v < %v = %v\n", xb, yb, 1)
+			x, y := stack.PopBigInt(), stack.PopBigInt()
+			if x.Cmp(y) < 0 {
+				stack.Push(One256)
+				vm.Debugf(" %v < %v = %v\n", x, y, 1)
 			} else {
 				stack.Push(Zero256)
-				vm.Debugf(" %v < %v = %v\n", xb, yb, 0)
+				vm.Debugf(" %v < %v = %v\n", x, y, 0)
 			}
 
 		case GT: // 0x11
-			x, y := stack.Pop(), stack.Pop()
-			xb := new(big.Int).SetBytes(x[:])
-			yb := new(big.Int).SetBytes(y[:])
-			if xb.Cmp(yb) > 0 {
-				stack.Push64(1)
-				vm.Debugf(" %v > %v = %v\n", xb, yb, 1)
+			x, y := stack.PopBigInt(), stack.PopBigInt()
+			if x.Cmp(y) > 0 {
+				stack.Push(One256)
+				vm.Debugf(" %v > %v = %v\n", x, y, 1)
 			} else {
 				stack.Push(Zero256)
-				vm.Debugf(" %v > %v = %v\n", xb, yb, 0)
+				vm.Debugf(" %v > %v = %v\n", x, y, 0)
 			}
 
 		case SLT: // 0x12
-			x, y := stack.Pop(), stack.Pop()
-			xb := S256(new(big.Int).SetBytes(x[:]))
-			yb := S256(new(big.Int).SetBytes(y[:]))
-			if xb.Cmp(yb) < 0 {
-				stack.Push64(1)
-				vm.Debugf(" %v < %v = %v\n", xb, yb, 1)
+			x, y := stack.PopBigIntSigned(), stack.PopBigIntSigned()
+			if x.Cmp(y) < 0 {
+				stack.Push(One256)
+				vm.Debugf(" %v < %v = %v\n", x, y, 1)
 			} else {
 				stack.Push(Zero256)
-				vm.Debugf(" %v < %v = %v\n", xb, yb, 0)
+				vm.Debugf(" %v < %v = %v\n", x, y, 0)
 			}
 
 		case SGT: // 0x13
-			x, y := stack.Pop(), stack.Pop()
-			xb := S256(new(big.Int).SetBytes(x[:]))
-			yb := S256(new(big.Int).SetBytes(y[:]))
-			if xb.Cmp(yb) > 0 {
-				stack.Push64(1)
-				vm.Debugf(" %v > %v = %v\n", xb, yb, 1)
+			x, y := stack.PopBigIntSigned(), stack.PopBigIntSigned()
+			if x.Cmp(y) > 0 {
+				stack.Push(One256)
+				vm.Debugf(" %v > %v = %v\n", x, y, 1)
 			} else {
 				stack.Push(Zero256)
-				vm.Debugf(" %v > %v = %v\n", xb, yb, 0)
+				vm.Debugf(" %v > %v = %v\n", x, y, 0)
 			}
 
 		case EQ: // 0x14
 			x, y := stack.Pop(), stack.Pop()
 			if bytes.Equal(x[:], y[:]) {
-				stack.Push64(1)
+				stack.Push(One256)
 				vm.Debugf(" %X == %X = %v\n", x, y, 1)
 			} else {
 				stack.Push(Zero256)
@@ -425,7 +369,7 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 		case ISZERO: // 0x15
 			x := stack.Pop()
 			if x.IsZero() {
-				stack.Push64(1)
+				stack.Push(One256)
 				vm.Debugf(" %X == 0 = %v\n", x, 1)
 			} else {
 				stack.Push(Zero256)
diff --git a/execution/execution.go b/execution/execution.go
index 09fd8c9f..ed822a71 100644
--- a/execution/execution.go
+++ b/execution/execution.go
@@ -301,7 +301,6 @@ func (exe *executor) Execute(tx txs.Tx) error {
 
 		// The logic in runCall MUST NOT return.
 		if exe.runCall {
-
 			// VM call variables
 			var (
 				gas     uint64             = tx.GasLimit
@@ -329,11 +328,11 @@ func (exe *executor) Execute(tx txs.Tx) error {
 				// that will take your fees
 				if outAcc == nil {
 					logging.InfoMsg(logger, "Call to address that does not exist",
-						"caller_address", inAcc.Address,
+						"caller_address", inAcc.Address(),
 						"callee_address", tx.Address)
 				} else {
 					logging.InfoMsg(logger, "Call to address that holds no code",
-						"caller_address", inAcc.Address,
+						"caller_address", inAcc.Address(),
 						"callee_address", tx.Address)
 				}
 				err = txs.ErrTxInvalidAddress
@@ -344,16 +343,17 @@ func (exe *executor) Execute(tx txs.Tx) error {
 			if createContract {
 				// We already checked for permission
 				callee = evm.DeriveNewAccount(caller, permission.GlobalAccountPermissions(exe.state))
-				logging.TraceMsg(logger, "Created new contract",
-					"contract_address", callee.Address,
-					"contract_code", callee.Code)
 				code = tx.Data
+				logging.TraceMsg(logger, "Creating new contract",
+					"contract_address", callee.Address(),
+					"init_code", code)
 			} else {
 				callee = acm.AsMutableAccount(outAcc)
-				logging.TraceMsg(logger, "Calling existing contract",
-					"contract_address", callee.Address,
-					"contract_code", callee.Code)
 				code = callee.Code()
+				logging.TraceMsg(logger, "Calling existing contract",
+					"contract_address", callee.Address(),
+					"input", tx.Data,
+					"contract_code", code)
 			}
 			logger.Trace("callee", callee.Address().String())
 
diff --git a/logging/config/filter_test.go b/logging/config/filter_test.go
index 5e847acb..9602fa71 100644
--- a/logging/config/filter_test.go
+++ b/logging/config/filter_test.go
@@ -115,5 +115,21 @@ func TestIncludeAnyFilterPredicate(t *testing.T) {
 	assert.False(t, fp([]interface{}{"Foo", "bar", "Shoes", 3427}))
 	assert.False(t, fp([]interface{}{"Foo", "bar", "Shoes", 42, "Bosh", "Bish"}))
 	assert.False(t, fp([]interface{}{"Food", 0.2, "Shoes", 42}))
+}
+
+func TestKeyOnlyPredicate(t *testing.T) {
 
+	fc := &FilterConfig{
+		FilterMode: IncludeWhenAnyMatches,
+		Predicates: []*KeyValuePredicateConfig{
+			{
+				KeyRegex: "Bosh",
+			},
+		},
+	}
+	fp, err := BuildFilterPredicate(fc)
+	assert.NoError(t, err)
+	assert.True(t, fp([]interface{}{"Foo", "bar", "Shoes", 3427}))
+	assert.False(t, fp([]interface{}{"Foo", "bar", "Shoes", 42, "Bosh", "Bish"}))
+	assert.True(t, fp([]interface{}{"Food", 0.2, "Shoes", 42}))
 }
diff --git a/logging/lifecycle/lifecycle.go b/logging/lifecycle/lifecycle.go
index 8d9428fd..e68a2602 100644
--- a/logging/lifecycle/lifecycle.go
+++ b/logging/lifecycle/lifecycle.go
@@ -57,9 +57,7 @@ func NewLoggerFromLoggingConfig(loggingConfig *config.LoggingConfig) (types.Info
 	go func() {
 		err := <-errCh.Out()
 		if err != nil {
-			logger.Info("logging_error", err,
-				"logging_config", loggingConfig.RootTOMLString(),
-				"logger", fmt.Sprintf("%#v", logger))
+			fmt.Printf("Logging error: %v", err)
 		}
 	}()
 
-- 
GitLab