mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	VM test framework.
This commit is contained in:
		
							parent
							
								
									a93547d9d1
								
							
						
					
					
						commit
						e9057d221c
					
				| @ -31,16 +31,16 @@ int daggerTest() | |||||||
| 	// Test dagger
 | 	// Test dagger
 | ||||||
| 	{ | 	{ | ||||||
| 		auto s = steady_clock::now(); | 		auto s = steady_clock::now(); | ||||||
| 		cout << hex << Dagger().eval((h256)1, (h256)0); | 		cout << hex << Dagger().eval((h256)(u256)1, (h256)(u256)0); | ||||||
| 		cout << " " << dec << duration_cast<milliseconds>(steady_clock::now() - s).count() << " ms" << endl; | 		cout << " " << dec << duration_cast<milliseconds>(steady_clock::now() - s).count() << " ms" << endl; | ||||||
| 		cout << hex << Dagger().eval((h256)1, (h256)1); | 		cout << hex << Dagger().eval((h256)(u256)1, (h256)(u256)1); | ||||||
| 		cout << " " << dec << duration_cast<milliseconds>(steady_clock::now() - s).count() << " ms" << endl; | 		cout << " " << dec << duration_cast<milliseconds>(steady_clock::now() - s).count() << " ms" << endl; | ||||||
| 	} | 	} | ||||||
| 	{ | 	{ | ||||||
| 		auto s = steady_clock::now(); | 		auto s = steady_clock::now(); | ||||||
| 		cout << hex << Dagger().eval((h256)1, (h256)0); | 		cout << hex << Dagger().eval((h256)(u256)1, (h256)(u256)0); | ||||||
| 		cout << " " << dec << duration_cast<milliseconds>(steady_clock::now() - s).count() << " ms" << endl; | 		cout << " " << dec << duration_cast<milliseconds>(steady_clock::now() - s).count() << " ms" << endl; | ||||||
| 		cout << hex << Dagger().eval((h256)1, (h256)1); | 		cout << hex << Dagger().eval((h256)(u256)1, (h256)(u256)1); | ||||||
| 		cout << " " << dec << duration_cast<milliseconds>(steady_clock::now() - s).count() << " ms" << endl; | 		cout << " " << dec << duration_cast<milliseconds>(steady_clock::now() - s).count() << " ms" << endl; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								main.cpp
									
									
									
									
									
								
							| @ -42,11 +42,11 @@ int main(int, char**) | |||||||
| 	std::cout << asHex(s.out()) << std::endl; | 	std::cout << asHex(s.out()) << std::endl; | ||||||
| 	std::cout << sha3(s.out()) << std::endl;*/ | 	std::cout << sha3(s.out()) << std::endl;*/ | ||||||
| 
 | 
 | ||||||
| 	hexPrefixTest(); | //	hexPrefixTest();
 | ||||||
| 	rlpTest(); | //	rlpTest();
 | ||||||
| 	trieTest(); | //	trieTest();
 | ||||||
| 	daggerTest(); | //	daggerTest();
 | ||||||
| 	cryptoTest(); | //	cryptoTest();
 | ||||||
| 	vmTest(); | 	vmTest(); | ||||||
| //	stateTest();
 | //	stateTest();
 | ||||||
| //	peerTest(argc, argv);
 | //	peerTest(argc, argv);
 | ||||||
|  | |||||||
							
								
								
									
										315
									
								
								vm.cpp
									
									
									
									
									
								
							
							
						
						
									
										315
									
								
								vm.cpp
									
									
									
									
									
								
							| @ -20,11 +20,15 @@ | |||||||
|  * State test functions. |  * State test functions. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <fstream> | ||||||
|  | #include "../json_spirit/json_spirit_reader_template.h" | ||||||
|  | #include "../json_spirit/json_spirit_writer_template.h" | ||||||
| #include <ExtVMFace.h> | #include <ExtVMFace.h> | ||||||
| #include <Transaction.h> | #include <Transaction.h> | ||||||
| #include <VM.h> | #include <VM.h> | ||||||
| #include <Instruction.h> | #include <Instruction.h> | ||||||
| using namespace std; | using namespace std; | ||||||
|  | using namespace json_spirit; | ||||||
| using namespace eth; | using namespace eth; | ||||||
| 
 | 
 | ||||||
| namespace eth | namespace eth | ||||||
| @ -33,37 +37,236 @@ namespace eth | |||||||
| class FakeExtVM: public ExtVMFace | class FakeExtVM: public ExtVMFace | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	FakeExtVM(Address _myAddress, u256 _myBalance, u256 _myNonce, u256s _myData, Address _txSender, u256 _txValue, u256s const& _txData, FeeStructure const& _fees, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber): | 	FakeExtVM() | ||||||
| 		ExtVMFace(_myAddress, _txSender, _txValue, _txData, _fees, _previousBlock, _currentBlock, _currentNumber) | 	{} | ||||||
| 	{ | 	FakeExtVM(FeeStructure const& _fees, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber): | ||||||
| 		reset(_myBalance, _myNonce, _myData); | 		ExtVMFace(Address(), Address(), 0, u256s(), _fees, _previousBlock, _currentBlock, _currentNumber) | ||||||
| 	} | 	{} | ||||||
| 
 | 
 | ||||||
| 	u256 store(u256 _n) { return get<3>(addresses[myAddress])[_n]; } | 	u256 store(u256 _n) { return get<3>(addresses[myAddress])[_n]; } | ||||||
| 	void setStore(u256 _n, u256 _v) { get<3>(addresses[myAddress])[_n] = _v; } | 	void setStore(u256 _n, u256 _v) { get<3>(addresses[myAddress])[_n] = _v; } | ||||||
| 	void mktx(Transaction& _t) { txs.push_back(_t); } | 	void mktx(Transaction& _t) | ||||||
|  | 	{ | ||||||
|  | 		if (get<0>(addresses[myAddress]) >= _t.value) | ||||||
|  | 		{ | ||||||
|  | 			get<0>(addresses[myAddress]) -= _t.value; | ||||||
|  | 			get<1>(addresses[myAddress])++; | ||||||
|  | //			get<0>(addresses[_t.receiveAddress]) += _t.value;
 | ||||||
|  | 			txs.push_back(_t); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	u256 balance(Address _a) { return get<0>(addresses[_a]); } | 	u256 balance(Address _a) { return get<0>(addresses[_a]); } | ||||||
| 	void payFee(bigint _fee) { get<0>(addresses[myAddress]) = (u256)(get<0>(addresses[myAddress]) - _fee); } | 	void payFee(bigint _fee) { get<0>(addresses[myAddress]) = (u256)(get<0>(addresses[myAddress]) - _fee); } | ||||||
| 	u256 txCount(Address _a) { return get<1>(addresses[_a]); } | 	u256 txCount(Address _a) { return get<1>(addresses[_a]); } | ||||||
| 	u256 extro(Address _a, u256 _pos) { return get<3>(addresses[_a])[_pos]; } | 	u256 extro(Address _a, u256 _pos) { return get<3>(addresses[_a])[_pos]; } | ||||||
| 	u256 extroPrice(Address _a) { return get<2>(addresses[_a]); } | 	u256 extroPrice(Address _a) { return get<2>(addresses[_a]); } | ||||||
| 	void suicide(Address _a) { dead = _a; } | 	void suicide(Address _a) | ||||||
|  | 	{ | ||||||
|  | 		for (auto const& i: get<3>(addresses[myAddress])) | ||||||
|  | 			if (i.second) | ||||||
|  | 				get<0>(addresses[_a]) += fees.m_memoryFee; | ||||||
|  | 		get<0>(addresses[_a]) += get<0>(addresses[myAddress]); | ||||||
|  | 		addresses.erase(myAddress); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void setTransaction(Address _txSender, u256 _txValue, u256s const& _txData) | ||||||
|  | 	{ | ||||||
|  | 		txSender = _txSender; | ||||||
|  | 		txValue = _txValue; | ||||||
|  | 		txData = _txData; | ||||||
|  | 	} | ||||||
|  | 	void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, u256s _myData) | ||||||
|  | 	{ | ||||||
|  | 		myAddress = _myAddress; | ||||||
|  | 		set(myAddress, _myBalance, _myNonce, _myData); | ||||||
|  | 	} | ||||||
|  | 	void set(Address _a, u256 _myBalance, u256 _myNonce, u256s _myData) | ||||||
|  | 	{ | ||||||
|  | 		get<0>(addresses[_a]) = _myBalance; | ||||||
|  | 		get<1>(addresses[_a]) = _myNonce; | ||||||
|  | 		get<2>(addresses[_a]) = 0; | ||||||
|  | 		for (unsigned i = 0; i < _myData.size(); ++i) | ||||||
|  | 			get<3>(addresses[_a])[i] = _myData[i]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mObject exportEnv() | ||||||
|  | 	{ | ||||||
|  | 		mObject ret; | ||||||
|  | 		ret["previousHash"] = toString(previousBlock.hash); | ||||||
|  | 		ret["previousNonce"] = toString(previousBlock.nonce); | ||||||
|  | 		push(ret, "currentDifficulty", currentBlock.difficulty); | ||||||
|  | 		push(ret, "currentTimestamp", currentBlock.timestamp); | ||||||
|  | 		ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress); | ||||||
|  | 		push(ret, "feeMultiplier", fees.multiplier()); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void importEnv(mObject& _o) | ||||||
|  | 	{ | ||||||
|  | 		previousBlock.hash = h256(_o["previousHash"].get_str()); | ||||||
|  | 		previousBlock.nonce = h256(_o["previousNonce"].get_str()); | ||||||
|  | 		currentBlock.difficulty = toInt(_o["currentDifficulty"]); | ||||||
|  | 		currentBlock.timestamp = toInt(_o["currentTimestamp"]); | ||||||
|  | 		currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); | ||||||
|  | 		fees.setMultiplier(toInt(_o["feeMultiplier"])); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	static u256 toInt(mValue const& _v) | ||||||
|  | 	{ | ||||||
|  | 		switch (_v.type()) | ||||||
|  | 		{ | ||||||
|  | 		case str_type: return u256(_v.get_str()); | ||||||
|  | 		case int_type: return (u256)_v.get_uint64(); | ||||||
|  | 		case bool_type: return (u256)(uint64_t)_v.get_bool(); | ||||||
|  | 		case real_type: return (u256)(uint64_t)_v.get_real(); | ||||||
|  | 		default: cwarn << "Bad type for scalar: " << _v.type(); | ||||||
|  | 		} | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	static void push(mObject& o, string const& _n, u256 _v) | ||||||
|  | 	{ | ||||||
|  | 		if (_v < (u256)1 << 64) | ||||||
|  | 			o[_n] = (uint64_t)_v; | ||||||
|  | 		else | ||||||
|  | 			o[_n] = toString(_v); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	static void push(mArray& a, u256 _v) | ||||||
|  | 	{ | ||||||
|  | 		if (_v < (u256)1 << 64) | ||||||
|  | 			a.push_back((uint64_t)_v); | ||||||
|  | 		else | ||||||
|  | 			a.push_back(toString(_v)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mObject exportState() | ||||||
|  | 	{ | ||||||
|  | 		mObject ret; | ||||||
|  | 		for (auto const& a: addresses) | ||||||
|  | 		{ | ||||||
|  | 			mObject o; | ||||||
|  | 			push(o, "balance", get<0>(a.second)); | ||||||
|  | 			push(o, "nonce", get<1>(a.second)); | ||||||
|  | 			push(o, "extroPrice", get<2>(a.second)); | ||||||
|  | 
 | ||||||
|  | 			mObject store; | ||||||
|  | 			string curKey; | ||||||
|  | 			u256 li = 0; | ||||||
|  | 			mArray curVal; | ||||||
|  | 			for (auto const& s: get<3>(a.second)) | ||||||
|  | 			{ | ||||||
|  | 				if (!li || s.first > li + 8) | ||||||
|  | 				{ | ||||||
|  | 					if (li) | ||||||
|  | 						store[curKey] = curVal; | ||||||
|  | 					li = s.first; | ||||||
|  | 					curKey = toString(li); | ||||||
|  | 					curVal = mArray(); | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 					for (; li != s.first; ++li) | ||||||
|  | 						curVal.push_back(0); | ||||||
|  | 				push(curVal, s.second); | ||||||
|  | 				++li; | ||||||
|  | 			} | ||||||
|  | 			if (li) | ||||||
|  | 			{ | ||||||
|  | 				store[curKey] = curVal; | ||||||
|  | 				o["store"] = store; | ||||||
|  | 			} | ||||||
|  | 			ret[toString(a.first)] = o; | ||||||
|  | 		} | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void importState(mObject& _o) | ||||||
|  | 	{ | ||||||
|  | 		for (auto const& i: _o) | ||||||
|  | 		{ | ||||||
|  | 			mObject o = i.second.get_obj(); | ||||||
|  | 			auto& a = addresses[Address(i.first)]; | ||||||
|  | 			get<0>(a) = toInt(o["balance"]); | ||||||
|  | 			get<1>(a) = toInt(o["nonce"]); | ||||||
|  | 			get<2>(a) = toInt(o["extroPrice"]); | ||||||
|  | 			if (o.count("store")) | ||||||
|  | 				for (auto const& j: o["store"].get_obj()) | ||||||
|  | 				{ | ||||||
|  | 					u256 adr(j.first); | ||||||
|  | 					for (auto const& k: j.second.get_array()) | ||||||
|  | 						get<3>(a)[adr++] = toInt(k); | ||||||
|  | 				} | ||||||
|  | 			if (o.count("code")) | ||||||
|  | 			{ | ||||||
|  | 				u256s d = compileLisp(o["code"].get_str()); | ||||||
|  | 				for (unsigned i = 0; i < d.size(); ++i) | ||||||
|  | 					get<3>(a)[(u256)i] = d[i]; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mObject exportExec() | ||||||
|  | 	{ | ||||||
|  | 		mObject ret; | ||||||
|  | 		ret["address"] = toString(myAddress); | ||||||
|  | 		ret["sender"] = toString(txSender); | ||||||
|  | 		push(ret, "value", txValue); | ||||||
|  | 		mArray d; | ||||||
|  | 		for (auto const& i: txData) | ||||||
|  | 			push(d, i); | ||||||
|  | 		ret["data"] = d; | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void importExec(mObject& _o) | ||||||
|  | 	{ | ||||||
|  | 		myAddress = Address(_o["address"].get_str()); | ||||||
|  | 		txSender = Address(_o["sender"].get_str()); | ||||||
|  | 		txValue = toInt(_o["value"]); | ||||||
|  | 		for (auto const& j: _o["data"].get_array()) | ||||||
|  | 			txData.push_back(toInt(j)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mArray exportTxs() | ||||||
|  | 	{ | ||||||
|  | 		mArray ret; | ||||||
|  | 		for (Transaction const& tx: txs) | ||||||
|  | 		{ | ||||||
|  | 			mObject o; | ||||||
|  | 			o["destination"] = toString(tx.receiveAddress); | ||||||
|  | 			push(o, "value", tx.value); | ||||||
|  | 			mArray d; | ||||||
|  | 			for (auto const& i: tx.data) | ||||||
|  | 				push(d, i); | ||||||
|  | 			o["data"] = d; | ||||||
|  | 			ret.push_back(o); | ||||||
|  | 		} | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void importTxs(mArray& _txs) | ||||||
|  | 	{ | ||||||
|  | 		for (mValue& v: _txs) | ||||||
|  | 		{ | ||||||
|  | 			auto tx = v.get_obj(); | ||||||
|  | 			Transaction t; | ||||||
|  | 			t.receiveAddress = Address(tx["destination"].get_str()); | ||||||
|  | 			t.value = toInt(tx["value"]); | ||||||
|  | 			for (auto const& j: tx["data"].get_array()) | ||||||
|  | 				t.data.push_back(toInt(j)); | ||||||
|  | 			txs.push_back(t); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	void reset(u256 _myBalance, u256 _myNonce, u256s _myData) | 	void reset(u256 _myBalance, u256 _myNonce, u256s _myData) | ||||||
| 	{ | 	{ | ||||||
| 		txs.clear(); | 		txs.clear(); | ||||||
| 		addresses.clear(); | 		addresses.clear(); | ||||||
| 		get<0>(addresses[myAddress]) = _myBalance; | 		set(myAddress, _myBalance, _myNonce, _myData); | ||||||
| 		get<1>(addresses[myAddress]) = _myNonce; |  | ||||||
| 		get<2>(addresses[myAddress]) = 0; |  | ||||||
| 		for (unsigned i = 0; i < _myData.size(); ++i) |  | ||||||
| 			get<3>(addresses[myAddress])[i] = _myData[i]; |  | ||||||
| 		dead = Address(); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	map<Address, tuple<u256, u256, u256, map<u256, u256>>> addresses; | 	map<Address, tuple<u256, u256, u256, map<u256, u256>>> addresses; | ||||||
| 	Transactions txs; | 	Transactions txs; | ||||||
| 	Address dead; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template <> class UnitTest<1> | template <> class UnitTest<1> | ||||||
| @ -71,6 +274,72 @@ template <> class UnitTest<1> | |||||||
| public: | public: | ||||||
| 	int operator()() | 	int operator()() | ||||||
| 	{ | 	{ | ||||||
|  | 		json_spirit::mValue v; | ||||||
|  | 		string s = asString(contents("/home/gav/Projects/cpp-ethereum/test/vmtests.json")); | ||||||
|  | 		cout << s << endl; | ||||||
|  | 		json_spirit::read_string(s, v); | ||||||
|  | 
 | ||||||
|  | 		doTests(v, true); | ||||||
|  | 
 | ||||||
|  | 		cout << json_spirit::write_string(v, true) << endl; | ||||||
|  | 
 | ||||||
|  | 		bool passed = doTests(v, false); | ||||||
|  | 
 | ||||||
|  | 		return passed ? 0 : 1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool doTests(json_spirit::mValue& v, bool _fillin) | ||||||
|  | 	{ | ||||||
|  | 		bool passed = true; | ||||||
|  | 		for (auto& i: v.get_obj()) | ||||||
|  | 		{ | ||||||
|  | 			cnote << i.first; | ||||||
|  | 			mObject& o = i.second.get_obj(); | ||||||
|  | 
 | ||||||
|  | 			VM vm; | ||||||
|  | 			FakeExtVM fev; | ||||||
|  | 			fev.importEnv(o["env"].get_obj()); | ||||||
|  | 			fev.importState(o["pre"].get_obj()); | ||||||
|  | 
 | ||||||
|  | 			if (_fillin) | ||||||
|  | 				o["pre"] = mValue(fev.exportState()); | ||||||
|  | 
 | ||||||
|  | 			for (auto i: o["exec"].get_array()) | ||||||
|  | 			{ | ||||||
|  | 				fev.importExec(i.get_obj()); | ||||||
|  | 				vm.go(fev); | ||||||
|  | 			} | ||||||
|  | 			if (_fillin) | ||||||
|  | 			{ | ||||||
|  | 				o["post"] = mValue(fev.exportState()); | ||||||
|  | 				o["txs"] = fev.exportTxs(); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				FakeExtVM test; | ||||||
|  | 				test.importState(o["post"].get_obj()); | ||||||
|  | 				test.importTxs(o["txs"].get_array()); | ||||||
|  | 				if (test.addresses != fev.addresses) | ||||||
|  | 				{ | ||||||
|  | 					cwarn << "Test failed: state different."; | ||||||
|  | 					passed = false; | ||||||
|  | 				} | ||||||
|  | 				if (test.txs != fev.txs) | ||||||
|  | 				{ | ||||||
|  | 					cwarn << "Test failed: tx list different:"; | ||||||
|  | 					cwarn << test.txs; | ||||||
|  | 					cwarn << fev.txs; | ||||||
|  | 					passed = false; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return passed; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	string makeTestCase() | ||||||
|  | 	{ | ||||||
|  | 		json_spirit::mObject o; | ||||||
|  | 
 | ||||||
| 		VM vm; | 		VM vm; | ||||||
| 		BlockInfo pb; | 		BlockInfo pb; | ||||||
| 		pb.hash = sha3("previousHash"); | 		pb.hash = sha3("previousHash"); | ||||||
| @ -81,15 +350,19 @@ public: | |||||||
| 		cb.coinbaseAddress = toAddress(sha3("coinbase")); | 		cb.coinbaseAddress = toAddress(sha3("coinbase")); | ||||||
| 		FeeStructure fees; | 		FeeStructure fees; | ||||||
| 		fees.setMultiplier(1); | 		fees.setMultiplier(1); | ||||||
| 
 | 		FakeExtVM fev(fees, pb, cb, 0); | ||||||
| 		string code = "(suicide (txsender))"; | 		fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))")); | ||||||
| 
 | 		o["env"] = fev.exportEnv(); | ||||||
| 		FakeExtVM fev(toAddress(sha3("contract")), ether, 0, compileLisp(code), toAddress(sha3("sender")), ether, u256s(), fees, pb, cb, 0); | 		o["pre"] = fev.exportState(); | ||||||
| 
 | 		fev.setTransaction(toAddress(sha3("sender")), ether, u256s()); | ||||||
|  | 		mArray execs; | ||||||
|  | 		execs.push_back(fev.exportExec()); | ||||||
|  | 		o["exec"] = execs; | ||||||
| 		vm.go(fev); | 		vm.go(fev); | ||||||
| 		cnote << fev.dead << formatBalance(fev.balance(toAddress(sha3("contract")))); | 		o["post"] = fev.exportState(); | ||||||
|  | 		o["txs"] = fev.exportTxs(); | ||||||
| 
 | 
 | ||||||
| 		return 0; | 		return json_spirit::write_string(json_spirit::mValue(o), true); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user