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
 | ||||
| 	{ | ||||
| 		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 << 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; | ||||
| 	} | ||||
| 	{ | ||||
| 		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 << 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; | ||||
| 	} | ||||
| 	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 << sha3(s.out()) << std::endl;*/ | ||||
| 
 | ||||
| 	hexPrefixTest(); | ||||
| 	rlpTest(); | ||||
| 	trieTest(); | ||||
| 	daggerTest(); | ||||
| 	cryptoTest(); | ||||
| //	hexPrefixTest();
 | ||||
| //	rlpTest();
 | ||||
| //	trieTest();
 | ||||
| //	daggerTest();
 | ||||
| //	cryptoTest();
 | ||||
| 	vmTest(); | ||||
| //	stateTest();
 | ||||
| //	peerTest(argc, argv);
 | ||||
|  | ||||
							
								
								
									
										315
									
								
								vm.cpp
									
									
									
									
									
								
							
							
						
						
									
										315
									
								
								vm.cpp
									
									
									
									
									
								
							| @ -20,11 +20,15 @@ | ||||
|  * 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 <Transaction.h> | ||||
| #include <VM.h> | ||||
| #include <Instruction.h> | ||||
| using namespace std; | ||||
| using namespace json_spirit; | ||||
| using namespace eth; | ||||
| 
 | ||||
| namespace eth | ||||
| @ -33,37 +37,236 @@ namespace eth | ||||
| class FakeExtVM: public ExtVMFace | ||||
| { | ||||
| 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): | ||||
| 		ExtVMFace(_myAddress, _txSender, _txValue, _txData, _fees, _previousBlock, _currentBlock, _currentNumber) | ||||
| 	{ | ||||
| 		reset(_myBalance, _myNonce, _myData); | ||||
| 	} | ||||
| 	FakeExtVM() | ||||
| 	{} | ||||
| 	FakeExtVM(FeeStructure const& _fees, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber): | ||||
| 		ExtVMFace(Address(), Address(), 0, u256s(), _fees, _previousBlock, _currentBlock, _currentNumber) | ||||
| 	{} | ||||
| 
 | ||||
| 	u256 store(u256 _n) { return get<3>(addresses[myAddress])[_n]; } | ||||
| 	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]); } | ||||
| 	void payFee(bigint _fee) { get<0>(addresses[myAddress]) = (u256)(get<0>(addresses[myAddress]) - _fee); } | ||||
| 	u256 txCount(Address _a) { return get<1>(addresses[_a]); } | ||||
| 	u256 extro(Address _a, u256 _pos) { return get<3>(addresses[_a])[_pos]; } | ||||
| 	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) | ||||
| 	{ | ||||
| 		txs.clear(); | ||||
| 		addresses.clear(); | ||||
| 		get<0>(addresses[myAddress]) = _myBalance; | ||||
| 		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(); | ||||
| 		set(myAddress, _myBalance, _myNonce, _myData); | ||||
| 	} | ||||
| 
 | ||||
| 	map<Address, tuple<u256, u256, u256, map<u256, u256>>> addresses; | ||||
| 	Transactions txs; | ||||
| 	Address dead; | ||||
| }; | ||||
| 
 | ||||
| template <> class UnitTest<1> | ||||
| @ -71,6 +274,72 @@ template <> class UnitTest<1> | ||||
| public: | ||||
| 	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; | ||||
| 		BlockInfo pb; | ||||
| 		pb.hash = sha3("previousHash"); | ||||
| @ -81,15 +350,19 @@ public: | ||||
| 		cb.coinbaseAddress = toAddress(sha3("coinbase")); | ||||
| 		FeeStructure fees; | ||||
| 		fees.setMultiplier(1); | ||||
| 
 | ||||
| 		string code = "(suicide (txsender))"; | ||||
| 
 | ||||
| 		FakeExtVM fev(toAddress(sha3("contract")), ether, 0, compileLisp(code), toAddress(sha3("sender")), ether, u256s(), fees, pb, cb, 0); | ||||
| 
 | ||||
| 		FakeExtVM fev(fees, pb, cb, 0); | ||||
| 		fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))")); | ||||
| 		o["env"] = fev.exportEnv(); | ||||
| 		o["pre"] = fev.exportState(); | ||||
| 		fev.setTransaction(toAddress(sha3("sender")), ether, u256s()); | ||||
| 		mArray execs; | ||||
| 		execs.push_back(fev.exportExec()); | ||||
| 		o["exec"] = execs; | ||||
| 		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