solidity编译出来bytecode不一样的问题分析

问题描述

使用remix 和 solcjs编译出来的bytecode不同(最后32+2字节不同)

源码分析

libsolidity/interface/CompilerStack.cpp


void CompilerStack::compileContract(
	ContractDefinition const& _contract,
	map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts
)
{
	if (
		_compiledContracts.count(&_contract) ||
		!_contract.annotation().unimplementedFunctions.empty() ||
		!_contract.constructorIsPublic()
	)
		return;
	for (auto const* dependency: _contract.annotation().contractDependencies)
		compileContract(*dependency, _compiledContracts);

	shared_ptr<Compiler> compiler = make_shared<Compiler>(m_optimize, m_optimizeRuns);
	Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
	
	// 此处创建出来的metadata包含了很多不确定的item, 再进行swarmHash操作, 结果自然不同
	string metadata = createMetadata(compiledContract);
    std::cout <<"metadata:" << __FILE__ << __LINE__ <<  metadata << std::endl;
	
	// 这里是固定的前缀  65627a7a72305820 加上 swarmHash(metadata)的结果
	bytes cborEncodedHash =
		// CBOR-encoding of the key "bzzr0"
		bytes{0x65, 'b', 'z', 'z', 'r', '0'}+
		// CBOR-encoding of the hash
		bytes{0x58, 0x20} + dev::swarmHash(metadata).asBytes();

    std::cout <<__FILE__ << __LINE__ <<" cborEncodedHash:" <<   toHex(cborEncodedHash) << std::endl;
	bytes cborEncodedMetadata;
	if (onlySafeExperimentalFeaturesActivated(_contract.sourceUnit().annotation().experimentalFeatures))
		cborEncodedMetadata =
			// CBOR-encoding of {"bzzr0": dev::swarmHash(metadata)}
			bytes{0xa1} +
			cborEncodedHash;
	else
		cborEncodedMetadata =
			// CBOR-encoding of {"bzzr0": dev::swarmHash(metadata), "experimental": true}
			bytes{0xa2} +
			cborEncodedHash +
			bytes{0x6c, 'e', 'x', 'p', 'e', 'r', 'i', 'm', 'e', 'n', 't', 'a', 'l', 0xf5};

    std::cout <<  __FILE__ << __LINE__ << " cborEncodedMetadata:" <<  toHex(cborEncodedMetadata) << std::endl; 
	solAssert(cborEncodedMetadata.size() <= 0xffff, "Metadata too large");
	// 16-bit big endian length
	cborEncodedMetadata += toCompactBigEndian(cborEncodedMetadata.size(), 2);
    std::cout <<  __FILE__ << __LINE__ <<  " cborEncodedMetadata bigEndian:" << toHex(cborEncodedMetadata) << std::endl; 
	compiler->compileContract(_contract, _compiledContracts, cborEncodedMetadata);
	compiledContract.compiler = compiler;

	try
	{
		compiledContract.object = compiler->assembledObject();
	}
	catch(eth::OptimizerException const&)
	{
		solAssert(false, "Assembly optimizer exception for bytecode");
	}
	catch(eth::AssemblyException const&)
	{
		solAssert(false, "Assembly exception for bytecode");
	}

	try
	{
		compiledContract.runtimeObject = compiler->runtimeObject();
	}
	catch(eth::OptimizerException const&)
	{
		solAssert(false, "Assembly optimizer exception for deployed bytecode");
	}
	catch(eth::AssemblyException const&)
	{
		solAssert(false, "Assembly exception for deployed bytecode");
	}

	compiledContract.metadata = metadata;
	_compiledContracts[compiledContract.contract] = &compiler->assembly();

	try
	{
		if (!_contract.isLibrary())
		{
			Compiler cloneCompiler(m_optimize, m_optimizeRuns);
			cloneCompiler.compileClone(_contract, _compiledContracts);
			compiledContract.cloneObject = cloneCompiler.assembledObject();
		}
	}
	catch (eth::AssemblyException const&)
	{
		// In some cases (if the constructor requests a runtime function), it is not
		// possible to compile the clone.

		// TODO: Report error / warning
	}
}

void Compiler::compileContract(
	ContractDefinition const& _contract,
	std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts,
	bytes const& _metadata
)
{
	ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize);
	runtimeCompiler.compileContract(_contract, _contracts);
	m_runtimeContext.appendAuxiliaryData(_metadata); //将一些metadata附加在尾部

	// This might modify m_runtimeContext because it can access runtime functions at
	// creation time.
	ContractCompiler creationCompiler(&runtimeCompiler, m_context, m_optimize);
	m_runtimeSub = creationCompiler.compileConstructor(_contract, _contracts);

	m_context.optimise(m_optimize, m_optimizeRuns);
}

string CompilerStack::createMetadata(Contract const& _contract) const
{
	Json::Value meta;
	meta["version"] = 1;
	meta["language"] = "Solidity";
	meta["compiler"]["version"] = VersionStringStrict;

	/// All the source files (including self), which should be included in the metadata.
	set<string> referencedSources;
	referencedSources.insert(_contract.contract->sourceUnit().annotation().path);
	for (auto const sourceUnit: _contract.contract->sourceUnit().referencedSourceUnits(true))
		referencedSources.insert(sourceUnit->annotation().path);

	meta["sources"] = Json::objectValue;
	for (auto const& s: m_sources)
	{
		if (!referencedSources.count(s.first))
			continue;

		solAssert(s.second.scanner, "Scanner not available");
		meta["sources"][s.first]["keccak256"] =
			"0x" + toHex(dev::keccak256(s.second.scanner->source()).asBytes());
		if (m_metadataLiteralSources)
			meta["sources"][s.first]["content"] = s.second.scanner->source();
		else
		{
			meta["sources"][s.first]["urls"] = Json::arrayValue;
			meta["sources"][s.first]["urls"].append(
				"bzzr://" + toHex(dev::swarmHash(s.second.scanner->source()).asBytes()) // 不确定的因素
			);
		}
	}
	meta["settings"]["optimizer"]["enabled"] = m_optimize;
	meta["settings"]["optimizer"]["runs"] = m_optimizeRuns;
	meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] =
		_contract.contract->annotation().canonicalName;

	meta["settings"]["remappings"] = Json::arrayValue;
	set<string> remappings;
	for (auto const& r: m_remappings)
		remappings.insert(r.context + ":" + r.prefix + "=" + r.target);
	for (auto const& r: remappings)
		meta["settings"]["remappings"].append(r);

	meta["settings"]["libraries"] = Json::objectValue;
	for (auto const& library: m_libraries)
		meta["settings"]["libraries"][library.first] = "0x" + toHex(library.second.asBytes());

	meta["output"]["abi"] = contractABI(_contract);
	meta["output"]["userdoc"] = natspecUser(_contract);
	meta["output"]["devdoc"] = natspecDev(_contract);

	return jsonCompactPrint(meta);
}

template <class T>
inline bytes toCompactBigEndian(T _val, unsigned _min = 0)
{
	static_assert(std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift
	int i = 0;
	for (T v = _val; v; ++i, v >>= 8) {}
	bytes ret(std::max<unsigned>(_min, i), 0);
	toBigEndian(_val, ret);
	return ret;
}

// Big-endian to/from host endian conversion functions.

/// Converts a templated integer value to the big-endian byte-stream represented on a templated collection.
/// The size of the collection object will be unchanged. If it is too small, it will not represent the
/// value properly, if too big then the additional elements will be zeroed out.
/// @a Out will typically be either std::string or bytes.
/// @a T will typically by unsigned, u160, u256 or bigint.
template <class T, class Out>
inline void toBigEndian(T _val, Out& o_out)
{
	static_assert(std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift
	for (auto i = o_out.size(); i != 0; _val >>= 8, i--)
	{
		T v = _val & (T)0xff;
		o_out[i - 1] = (typename Out::value_type)(uint8_t)v;
	}
}

测试

abc.sol

pragma solidity ^0.4.18;
contract AJCToken {
}
./solc  --bin abc.sol
metadata:/home/yqq/mine/solidity/ethereum-solidity/libsolidity/interface/CompilerStack.cpp683{"compiler":{"version":"0.4.20-develop.2020.11.17+commit.3155dd80.mod"},"language":"Solidity","output":{"abi":[],"devdoc":{"methods":{}},"userdoc":{"methods":{}}},"settings":{"compilationTarget":{"abc.sol":"AJCToken"},"libraries":{},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"abc.sol":{"keccak256":"0xe808e3b5f0e032c4f1a347995c9e634ddc96af6e2a12997a7f7bd8122c9bef63","urls":["bzzr://924d33467bd8f8751e740fb2b35990532ad31872f46a0aa456136342e9464a00"]}},"version":1}
/home/yqq/mine/solidity/ethereum-solidity/libsolidity/interface/CompilerStack.cpp690 cborEncodedHash:65627a7a72305820c883c4be5a32d6c09e2b5d3a2f49d69f1e5e5012d043a8a11d2fcf2db3fed437
/home/yqq/mine/solidity/ethereum-solidity/libsolidity/interface/CompilerStack.cpp704 cborEncodedMetadata:a165627a7a72305820c883c4be5a32d6c09e2b5d3a2f49d69f1e5e5012d043a8a11d2fcf2db3fed437
/home/yqq/mine/solidity/ethereum-solidity/libsolidity/interface/CompilerStack.cpp708 cborEncodedMetadata bigEndian:a165627a7a72305820c883c4be5a32d6c09e2b5d3a2f49d69f1e5e5012d043a8a11d2fcf2db3fed4370029
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp661ret.bytecode: 6060604052600080fd00
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp663ret.bytecode + m_auxiliaryData: 6060604052600080fd00a165627a7a72305820c883c4be5a32d6c09e2b5d3a2f49d69f1e5e5012d043a8a11d2fcf2db3fed4370029
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp670ret.bytecode bigendian:6060604052600080fd00a165627a7a72305820c883c4be5a32d6c09e2b5d3a2f49d69f1e5e5012d043a8a11d2fcf2db3fed4370029
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp661ret.bytecode: 60606040523415600e57600080fd5b603580601b6000396000f3006060604052600080fd00a165627a7a72305820c883c4be5a32d6c09e2b5d3a2f49d69f1e5e5012d043a8a11d2fcf2db3fed4370029
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp663ret.bytecode + m_auxiliaryData: 60606040523415600e57600080fd5b603580601b6000396000f3006060604052600080fd00a165627a7a72305820c883c4be5a32d6c09e2b5d3a2f49d69f1e5e5012d043a8a11d2fcf2db3fed4370029
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp670ret.bytecode bigendian:60606040523415600e57600080fd5b603580601b6000396000f3006060604052600080fd00a165627a7a72305820c883c4be5a32d6c09e2b5d3a2f49d69f1e5e5012d043a8a11d2fcf2db3fed4370029
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp661ret.bytecode: 
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp663ret.bytecode + m_auxiliaryData: 
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp670ret.bytecode bigendian:
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp661ret.bytecode: 36600080376020600036600073cafecafecafecafecafecafecafecafecafecafe6102c65a03f41515602d57fe5b60206000f3
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp663ret.bytecode + m_auxiliaryData: 36600080376020600036600073cafecafecafecafecafecafecafecafecafecafe6102c65a03f41515602d57fe5b60206000f3
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp670ret.bytecode bigendian:36600080376020600036600073cafecafecafecafecafecafecafecafecafecafe6102c65a03f41515602d57fe5b60206000f3
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp661ret.bytecode: 
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp663ret.bytecode + m_auxiliaryData: 
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp670ret.bytecode bigendian:
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp661ret.bytecode: 60606040523415600e57600080fd5b603380601b6000396000f30036600080376020600036600073cafecafecafecafecafecafecafecafecafecafe6102c65a03f41515602d57fe5b60206000f3
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp663ret.bytecode + m_auxiliaryData: 60606040523415600e57600080fd5b603380601b6000396000f30036600080376020600036600073cafecafecafecafecafecafecafecafecafecafe6102c65a03f41515602d57fe5b60206000f3
/home/yqq/mine/solidity/ethereum-solidity/libevmasm/Assembly.cpp670ret.bytecode bigendian:60606040523415600e57600080fd5b603380601b6000396000f30036600080376020600036600073cafecafecafecafecafecafecafecafecafecafe6102c65a03f41515602d57fe5b60206000f3
Warning: This is a pre-release compiler version, please do not use it in production.


======= abc.sol:AJCToken =======
Binary: 
60606040523415600e57600080fd5b603580601b6000396000f3006060604052600080fd00a165627a7a72305820c883c4be5a32d6c09e2b5d3a2f49d69f1e5e5012d043a8a11d2fcf2db3fed4370029

分析输出结果:

60606040523415600e57600080fd5b603580601b6000396000f3006060604052600080fd00a165627a7a72305820c883c4be5a32d6c09e2b5d3a2f49d69f1e5e5012d043a8a11d2fcf2db3fed4370029

第一部分: 60606040523415600e57600080fd5b603580601b6000396000f3006060604052600080fd00
第二部分: 
    a165627a7a72305820 // 固定前缀
    c883c4be5a32d6c09e2b5d3a2f49d69f1e5e5012d043a8a11d2fcf2db3fed437 //swarmHash(metadata)
    0029 //经过toCompactBigEndian之后附加的内容

结论

最后的不同的字节是metadata相关信息, 不属于代码的bytecode

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: soliditybytecode是经过编译生成字节码,其中包含了合约的二进制代码和一些元数据。如果你已经拥有了bytecode,那么你可以使用solidity的官方工具solc将bytecode转换成abi。在命令行中运行以下命令即可: ``` solc --abi <your_contract_bytecode> ``` 在这里,`<your_contract_bytecode>`是你的合约字节码。执行上述命令后,会生成一个JSON格式的abi文件,其中包含了你的合约的函数名、参数类型、返回类型等信息。 ### 回答2: 在Solidity中,字节码bytecode)是由智能合约源代码编译生成的机器码指令序列,而ABI(Application Binary Interface)是用于与合约进行交互的接口描述。反编译字节码以获取ABI的过程如下所示: 1. 使用Solidity编译器(solc)将Solidity源代码编译字节码。这可以通过命令行工具(solc)或使用Solidity插件进行。 2. 获取编译后的字节码bytecode)。一般来说,编译器生成合约的部署字节码和运行时字节码。部署字节码用于在区块链上创建新的合约实例,而运行时字节码用于执行合约中的方法。 3. 使用反编译工具将字节码编译为汇编代码。有几种工具可以实现这一步骤,如Etherscan的工具,它可以将部署字节码和运行时字节码转换为可读的汇编代码。 4. 根据反编译的汇编代码推导出ABI。反编译的汇编代码将显示每个函数的入口点和参数类型等信息。根据这些信息,可以手动创建ABI,或使用相关工具从汇编代码中提取并自动生成ABI。 需要注意的是,由于编译器的优化等因素,反编译得到的汇编代码可能不完全准确,某些信息(如内部函数、变量名)可能会丢失。因此,在实际应用中,最好使用在编译阶段生成的ABI,而不是依赖于反编译出来的版本。 ### 回答3: 要反编译 Solidity字节码bytecode)以获取 ABI(应用程序二进制接口),我们可以使用一些工具和步骤: 1. 使用 Solidity 编译器智能合约源代码编译字节码。例如,使用 solc 命令行工具:`solc --bin <contract_filename.sol>`。这将生成合约的字节码文件。 2. 将字节码转换为可读格式。字节码通常是以十六进制表示的。我们可以使用 Solidity 的库函数来将其转换为可读的格式。在 Solidity 中使用以下函数:`bytes memory bytecode = hex"字节码"`。 3. 使用反编译工具将字节码转换为 ABI。目前,有一些可用的工具可以帮助我们将 Solidity 字节码转换为 ABI。 - Solidity Assembly 是一种受到 EVM 指令集影响的低级语言。您可以使用 Solidity Assembly 编写代码并将其转换为 ABI。示例代码如下: ``` pragma solidity ^0.8.0; contract BytecodeParser { function getABI(bytes memory _bytecode) public pure returns (string[] memory) { assembly { let ptr := add(_bytecode, 0x20) let length := mload(_bytecode) let result := mload(0x40) // allocate memory for the ABI mstore(result, 0x20) // set length of the array to 1 mstore(add(result, 0x20), length) // store the length of the bytecode as the first element mstore(add(result, 0x40), ptr) // store the bytecode as the second element return(result, 0x60) } } } ``` - Mythril 是一个开源的智能合约扫描工具,也可以用于反编译 Solidity 字节码。安装 Mythril 并使用以下命令:`myth -x <Bytecode_File_Path>`。 - Remix IDE 是一个具有反编译功能的 Solidity 开发环境。在 Remix IDE 中,您可以上传字节码文件并选择反编译功能以获取 ABI。 请注意,由于 Solidity 字节码是通过编译过程中的优化生成的,所以在某些情况下,反编译出的 ABI 可能不完全准确。因此,在实际使用过程中,最好通过查看合约的源代码来获取准确的 ABI。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值