transaction_test_util.go 6.6 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
	"runtime"

	"github.com/ethereum/go-ethereum/common"
27
	"github.com/ethereum/go-ethereum/core"
28
	"github.com/ethereum/go-ethereum/core/types"
Taylor Gerring's avatar
Taylor Gerring committed
29
	"github.com/ethereum/go-ethereum/logger/glog"
30
	"github.com/ethereum/go-ethereum/params"
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
	"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 {
48
	Blocknumber string
49 50 51 52 53
	Rlp         string
	Sender      string
	Transaction TtTransaction
}

54 55 56
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
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
		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
}

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

87
	if err := runTransactionTests(tests, skipTests); err != nil {
88 89
		return err
	}
90 91
	return nil
}
92

93 94 95 96 97 98 99
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 {
100 101
		// if the test should be skipped, return
		if skipTest[name] {
Taylor Gerring's avatar
Taylor Gerring committed
102
			glog.Infoln("Skipping transaction test", name)
103 104
			return nil
		}
Taylor Gerring's avatar
Taylor Gerring committed
105

106
		// test the block
Taylor Gerring's avatar
Taylor Gerring committed
107
		if err := runTransactionTest(test); err != nil {
108
			return fmt.Errorf("%s: %v", name, err)
109
		}
Taylor Gerring's avatar
Taylor Gerring committed
110
		glog.Infoln("Transaction test passed: ", name)
111

112 113 114 115
	}
	return nil
}

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

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

	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)
148
			return fmt.Errorf("Field validations failed after RLP decoding: %s", validationError)
149 150 151 152 153 154 155 156 157 158 159 160 161 162
		}
	}
	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)
		}
	}()

163 164 165 166
	var (
		decodedSender common.Address
	)

167 168
	chainConfig := &core.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock}
	if chainConfig.IsHomestead(common.String2Big(txTest.Blocknumber)) {
169 170 171 172
		decodedSender, err = decodedTx.From()
	} else {
		decodedSender, err = decodedTx.FromFrontier()
	}
173 174 175 176
	if err != nil {
		return err
	}

177 178 179
	expectedSender := mustConvertAddress(txTest.Sender)
	if expectedSender != decodedSender {
		return fmt.Errorf("Sender mismatch: %v %v", expectedSender, decodedSender)
180
	}
181 182

	expectedData := mustConvertBytes(txTest.Transaction.Data)
183 184
	if !bytes.Equal(expectedData, decodedTx.Data()) {
		return fmt.Errorf("Tx input data mismatch: %#v %#v", expectedData, decodedTx.Data())
185
	}
186 187

	expectedGasLimit := mustConvertBigInt(txTest.Transaction.GasLimit, 16)
188 189
	if expectedGasLimit.Cmp(decodedTx.Gas()) != 0 {
		return fmt.Errorf("GasLimit mismatch: %v %v", expectedGasLimit, decodedTx.Gas())
190
	}
191 192

	expectedGasPrice := mustConvertBigInt(txTest.Transaction.GasPrice, 16)
193 194
	if expectedGasPrice.Cmp(decodedTx.GasPrice()) != 0 {
		return fmt.Errorf("GasPrice mismatch: %v %v", expectedGasPrice, decodedTx.GasPrice())
195
	}
196 197

	expectedNonce := mustConvertUint(txTest.Transaction.Nonce, 16)
198 199
	if expectedNonce != decodedTx.Nonce() {
		return fmt.Errorf("Nonce mismatch: %v %v", expectedNonce, decodedTx.Nonce())
200
	}
201

202 203 204 205
	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)
206
	}
207 208 209
	expectedS := mustConvertBigInt(txTest.Transaction.S, 16)
	if s.Cmp(expectedS) != 0 {
		return fmt.Errorf("S mismatch: %v %v", expectedS, s)
210
	}
211
	expectedV := mustConvertUint(txTest.Transaction.V, 16)
212 213
	if uint64(v) != expectedV {
		return fmt.Errorf("V mismatch: %v %v", expectedV, v)
214
	}
215 216

	expectedTo := mustConvertAddress(txTest.Transaction.To)
217
	if decodedTx.To() == nil {
218 219 220 221
		if expectedTo != common.BytesToAddress([]byte{}) { // "empty" or "zero" address
			return fmt.Errorf("To mismatch when recipient is nil (contract creation): %v", expectedTo)
		}
	} else {
222 223
		if expectedTo != *decodedTx.To() {
			return fmt.Errorf("To mismatch: %v %v", expectedTo, *decodedTx.To())
224
		}
225
	}
226

227
	expectedValue := mustConvertBigInt(txTest.Transaction.Value, 16)
228 229
	if expectedValue.Cmp(decodedTx.Value()) != 0 {
		return fmt.Errorf("Value mismatch: %v %v", expectedValue, decodedTx.Value())
230 231 232 233
	}

	return nil
}