transaction_test_util.go 6.22 KB
Newer Older
1
// Copyright 2015 The go-ethereum Authors
2
// This file is part of the go-ethereum library.
3
//
4
// The go-ethereum library is free software: you can redistribute it and/or modify
5 6 7 8
// 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.
//
9
// The go-ethereum library is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 13 14
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
15
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16

17 18 19 20
package tests

import (
	"bytes"
21
	"errors"
22
	"fmt"
Taylor Gerring's avatar
Taylor Gerring committed
23
	"io"
24 25 26 27
	"runtime"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
Taylor Gerring's avatar
Taylor Gerring committed
28
	"github.com/ethereum/go-ethereum/logger/glog"
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
	"github.com/ethereum/go-ethereum/rlp"
)

// Transaction Test JSON Format
type TtTransaction struct {
	Data     string
	GasLimit string
	GasPrice string
	Nonce    string
	R        string
	S        string
	To       string
	V        string
	Value    string
}

type TransactionTest struct {
	Rlp         string
	Sender      string
	Transaction TtTransaction
}

51 52 53
func RunTransactionTestsWithReader(r io.Reader, skipTests []string) error {
	skipTest := make(map[string]bool, len(skipTests))
	for _, name := range skipTests {
Taylor Gerring's avatar
Taylor Gerring committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
		skipTest[name] = true
	}

	bt := make(map[string]TransactionTest)
	if err := readJson(r, &bt); err != nil {
		return err
	}

	for name, test := range bt {
		// if the test should be skipped, return
		if skipTest[name] {
			glog.Infoln("Skipping transaction test", name)
			return nil
		}
		// test the block
		if err := runTransactionTest(test); err != nil {
			return err
		}
		glog.Infoln("Transaction test passed: ", name)

	}
	return nil
}

78 79 80 81
func RunTransactionTests(file string, skipTests []string) error {
	tests := make(map[string]TransactionTest)
	if err := readJsonFile(file, &tests); err != nil {
		return err
82 83
	}

84
	if err := runTransactionTests(tests, skipTests); err != nil {
85 86
		return err
	}
87 88
	return nil
}
89

90 91 92 93 94 95 96
func runTransactionTests(tests map[string]TransactionTest, skipTests []string) error {
	skipTest := make(map[string]bool, len(skipTests))
	for _, name := range skipTests {
		skipTest[name] = true
	}

	for name, test := range tests {
97 98
		// if the test should be skipped, return
		if skipTest[name] {
Taylor Gerring's avatar
Taylor Gerring committed
99
			glog.Infoln("Skipping transaction test", name)
100 101
			return nil
		}
Taylor Gerring's avatar
Taylor Gerring committed
102

103
		// test the block
Taylor Gerring's avatar
Taylor Gerring committed
104
		if err := runTransactionTest(test); err != nil {
105
			return err
106
		}
Taylor Gerring's avatar
Taylor Gerring committed
107
		glog.Infoln("Transaction test passed: ", name)
108

109 110 111 112
	}
	return nil
}

Taylor Gerring's avatar
Taylor Gerring committed
113
func runTransactionTest(txTest TransactionTest) (err error) {
114 115
	tx := new(types.Transaction)
	err = rlp.DecodeBytes(mustConvertBytes(txTest.Rlp), tx)
116 117

	if err != nil {
118 119
		if txTest.Sender == "" {
			// RLP decoding failed and this is expected (test OK)
120 121
			return nil
		} else {
122
			// RLP decoding failed but is expected to succeed (test FAIL)
123
			return fmt.Errorf("RLP decoding failed when expected to succeed: ", err)
124 125
		}
	}
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

	validationError := verifyTxFields(txTest, tx)
	if txTest.Sender == "" {
		if validationError != nil {
			// RLP decoding works but validation should fail (test OK)
			return nil
		} else {
			// RLP decoding works but validation should fail (test FAIL)
			// (this should not be possible but added here for completeness)
			return errors.New("Field validations succeeded but should fail")
		}
	}

	if txTest.Sender != "" {
		if validationError == nil {
			// RLP decoding works and validations pass (test OK)
			return nil
		} else {
			// RLP decoding works and validations pass (test FAIL)
145
			return fmt.Errorf("Field validations failed after RLP decoding: ", validationError)
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
		}
	}
	return errors.New("Should not happen: verify RLP decoding and field validation")
}

func verifyTxFields(txTest TransactionTest, decodedTx *types.Transaction) (err error) {
	defer func() {
		if recovered := recover(); recovered != nil {
			buf := make([]byte, 64<<10)
			buf = buf[:runtime.Stack(buf, false)]
			err = fmt.Errorf("%v\n%s", recovered, buf)
		}
	}()

	decodedSender, err := decodedTx.From()
161 162 163 164
	if err != nil {
		return err
	}

165 166 167
	expectedSender := mustConvertAddress(txTest.Sender)
	if expectedSender != decodedSender {
		return fmt.Errorf("Sender mismatch: %v %v", expectedSender, decodedSender)
168
	}
169 170

	expectedData := mustConvertBytes(txTest.Transaction.Data)
171 172
	if !bytes.Equal(expectedData, decodedTx.Data()) {
		return fmt.Errorf("Tx input data mismatch: %#v %#v", expectedData, decodedTx.Data())
173
	}
174 175

	expectedGasLimit := mustConvertBigInt(txTest.Transaction.GasLimit, 16)
176 177
	if expectedGasLimit.Cmp(decodedTx.Gas()) != 0 {
		return fmt.Errorf("GasLimit mismatch: %v %v", expectedGasLimit, decodedTx.Gas())
178
	}
179 180

	expectedGasPrice := mustConvertBigInt(txTest.Transaction.GasPrice, 16)
181 182
	if expectedGasPrice.Cmp(decodedTx.GasPrice()) != 0 {
		return fmt.Errorf("GasPrice mismatch: %v %v", expectedGasPrice, decodedTx.GasPrice())
183
	}
184 185

	expectedNonce := mustConvertUint(txTest.Transaction.Nonce, 16)
186 187
	if expectedNonce != decodedTx.Nonce() {
		return fmt.Errorf("Nonce mismatch: %v %v", expectedNonce, decodedTx.Nonce())
188
	}
189

190 191 192 193
	v, r, s := decodedTx.SignatureValues()
	expectedR := mustConvertBigInt(txTest.Transaction.R, 16)
	if r.Cmp(expectedR) != 0 {
		return fmt.Errorf("R mismatch: %v %v", expectedR, r)
194
	}
195 196 197
	expectedS := mustConvertBigInt(txTest.Transaction.S, 16)
	if s.Cmp(expectedS) != 0 {
		return fmt.Errorf("S mismatch: %v %v", expectedS, s)
198
	}
199
	expectedV := mustConvertUint(txTest.Transaction.V, 16)
200 201
	if uint64(v) != expectedV {
		return fmt.Errorf("V mismatch: %v %v", expectedV, v)
202
	}
203 204

	expectedTo := mustConvertAddress(txTest.Transaction.To)
205
	if decodedTx.To() == nil {
206 207 208 209
		if expectedTo != common.BytesToAddress([]byte{}) { // "empty" or "zero" address
			return fmt.Errorf("To mismatch when recipient is nil (contract creation): %v", expectedTo)
		}
	} else {
210 211
		if expectedTo != *decodedTx.To() {
			return fmt.Errorf("To mismatch: %v %v", expectedTo, *decodedTx.To())
212
		}
213
	}
214

215
	expectedValue := mustConvertBigInt(txTest.Transaction.Value, 16)
216 217
	if expectedValue.Cmp(decodedTx.Value()) != 0 {
		return fmt.Errorf("Value mismatch: %v %v", expectedValue, decodedTx.Value())
218 219 220 221
	}

	return nil
}