const& _h)
{
- return (*this |= _h.template bloom());
+ return (*this |= _h.template bloomPart
());
}
template inline bool containsBloom(FixedHash const& _h)
{
- return contains(_h.template bloom());
+ return contains(_h.template bloomPart
());
}
- template inline FixedHash bloom() const
+ template inline FixedHash bloomPart() const
{
+ static_assert((M & (M - 1)) == 0, "M must be power-of-two");
static const unsigned c_bloomBits = M * 8;
unsigned mask = c_bloomBits - 1;
unsigned bloomBytes = (dev::toLog2(c_bloomBits) + 7) / 8;
diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp
index 6c2f8269a..b160cdd94 100644
--- a/libethash-cl/ethash_cl_miner.cpp
+++ b/libethash-cl/ethash_cl_miner.cpp
@@ -429,7 +429,8 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
};
queue pending;
- static uint32_t const c_zero = 0;
+ // this can't be a static because in MacOSX OpenCL implementation a segfault occurs when a static is passed to OpenCL functions
+ uint32_t const c_zero = 0;
// update header constant buffer
m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header);
diff --git a/libethash-cl/ethash_cl_miner_kernel.cl b/libethash-cl/ethash_cl_miner_kernel.cl
index 2143435ed..8ea6df12d 100644
--- a/libethash-cl/ethash_cl_miner_kernel.cl
+++ b/libethash-cl/ethash_cl_miner_kernel.cl
@@ -36,7 +36,7 @@ __constant uint2 const Keccak_f1600_RC[24] = {
(uint2)(0x80008008, 0x80000000),
};
-void keccak_f1600_round(uint2* a, uint r, uint out_size)
+static void keccak_f1600_round(uint2* a, uint r, uint out_size)
{
#if !__ENDIAN_LITTLE__
for (uint i = 0; i != 25; ++i)
@@ -152,7 +152,7 @@ void keccak_f1600_round(uint2* a, uint r, uint out_size)
#endif
}
-void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate)
+static void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate)
{
for (uint i = in_size; i != 25; ++i)
{
@@ -194,17 +194,17 @@ void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate)
#define countof(x) (sizeof(x) / sizeof(x[0]))
-uint fnv(uint x, uint y)
+static uint fnv(uint x, uint y)
{
return x * FNV_PRIME ^ y;
}
-uint4 fnv4(uint4 x, uint4 y)
+static uint4 fnv4(uint4 x, uint4 y)
{
return x * FNV_PRIME ^ y;
}
-uint fnv_reduce(uint4 v)
+static uint fnv_reduce(uint4 v)
{
return fnv(fnv(fnv(v.x, v.y), v.z), v.w);
}
@@ -227,7 +227,7 @@ typedef union
uint4 uint4s[128 / sizeof(uint4)];
} hash128_t;
-hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
+static hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
{
hash64_t init;
uint const init_size = countof(init.ulongs);
@@ -243,7 +243,7 @@ hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
return init;
}
-uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, __global hash128_t const* g_dag1, __global hash128_t const* g_dag2, __global hash128_t const* g_dag3, uint isolate)
+static uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, __global hash128_t const* g_dag1, __global hash128_t const* g_dag2, __global hash128_t const* g_dag3, uint isolate)
{
uint4 mix = init;
@@ -277,7 +277,7 @@ uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global
-uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate)
+static uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate)
{
uint4 mix = init;
@@ -311,7 +311,7 @@ uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash12
}
-hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
+static hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
{
ulong state[25];
@@ -330,7 +330,7 @@ hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
return hash;
}
-hash32_t compute_hash_simple(
+static hash32_t compute_hash_simple(
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong nonce,
@@ -383,7 +383,7 @@ typedef union
} compute_hash_share;
-hash32_t compute_hash(
+static hash32_t compute_hash(
__local compute_hash_share* share,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
@@ -427,7 +427,7 @@ hash32_t compute_hash(
}
-hash32_t compute_hash_chunks(
+static hash32_t compute_hash_chunks(
__local compute_hash_share* share,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
diff --git a/libethash/endian.h b/libethash/endian.h
index 0ee402d9a..6ca6cc036 100644
--- a/libethash/endian.h
+++ b/libethash/endian.h
@@ -32,6 +32,9 @@
#include
#define ethash_swap_u32(input_) OSSwapInt32(input_)
#define ethash_swap_u64(input_) OSSwapInt64(input_)
+#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
+#define ethash_swap_u32(input_) bswap32(input_)
+#define ethash_swap_u64(input_) bswap64(input_)
#else // posix
#include
#define ethash_swap_u32(input_) __bswap_32(input_)
diff --git a/libethash/internal.c b/libethash/internal.c
index 26378e56e..a050d5b48 100644
--- a/libethash/internal.c
+++ b/libethash/internal.c
@@ -284,13 +284,13 @@ bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
- ethash_h256_t const* difficulty
+ ethash_h256_t const* boundary
)
{
ethash_h256_t return_hash;
ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash);
- return ethash_check_difficulty(&return_hash, difficulty);
+ return ethash_check_difficulty(&return_hash, boundary);
}
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed)
diff --git a/libethash/internal.h b/libethash/internal.h
index 4e2b695ac..26c395ad6 100644
--- a/libethash/internal.h
+++ b/libethash/internal.h
@@ -46,27 +46,36 @@ static inline void ethash_h256_reset(ethash_h256_t* hash)
memset(hash, 0, 32);
}
-// Returns if hash is less than or equal to difficulty
+// Returns if hash is less than or equal to boundary (2^256/difficulty)
static inline bool ethash_check_difficulty(
ethash_h256_t const* hash,
- ethash_h256_t const* difficulty
+ ethash_h256_t const* boundary
)
{
- // Difficulty is big endian
+ // Boundary is big endian
for (int i = 0; i < 32; i++) {
- if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) {
+ if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) {
continue;
}
- return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i);
+ return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i);
}
return true;
}
+/**
+ * Difficulty quick check for POW preverification
+ *
+ * @param header_hash The hash of the header
+ * @param nonce The block's nonce
+ * @param mix_hash The mix digest hash
+ * @param boundary The boundary is defined as (2^256 / difficulty)
+ * @return true for succesful pre-verification and false otherwise
+ */
bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
- ethash_h256_t const* difficulty
+ ethash_h256_t const* boundary
);
struct ethash_light {
diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp
index bacbecc3f..6821b2362 100644
--- a/libethereum/EthereumHost.cpp
+++ b/libethereum/EthereumHost.cpp
@@ -292,8 +292,8 @@ void EthereumHost::onPeerStatus(EthereumPeer* _peer)
else
_peer->m_expectedHashes = estimatedHashes;
continueSync(_peer);
+ DEV_INVARIANT_CHECK;
}
- DEV_INVARIANT_CHECK;
}
unsigned EthereumHost::estimateHashes()
@@ -313,6 +313,7 @@ unsigned EthereumHost::estimateHashes()
void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes)
{
RecursiveGuard l(x_sync);
+ DEV_INVARIANT_CHECK;
if (_peer->m_syncHashNumber > 0)
_peer->m_syncHashNumber += _hashes.size();
@@ -322,7 +323,6 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes)
void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete)
{
- DEV_INVARIANT_CHECK;
if (_hashes.empty())
{
_peer->m_hashSub.doneFetch();
@@ -454,7 +454,8 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
unsigned unknown = 0;
unsigned got = 0;
unsigned repeated = 0;
- h256 lastUnknown;
+ u256 maxDifficulty = 0;
+ h256 maxUnknown;
for (unsigned i = 0; i < itemCount; ++i)
{
@@ -483,9 +484,17 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
break;
case ImportResult::UnknownParent:
- lastUnknown = h;
+ {
unknown++;
+ BlockInfo bi;
+ bi.populateFromHeader(_r[i][0]);
+ if (bi.difficulty > maxDifficulty)
+ {
+ maxDifficulty = bi.difficulty;
+ maxUnknown = h;
+ }
break;
+ }
default:;
}
@@ -501,8 +510,10 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
if (m_state == SyncState::NewBlocks && unknown > 0)
{
- _peer->m_latestHash = lastUnknown;
- resetSyncTo(lastUnknown);
+ _peer->m_latestHash = maxUnknown;
+ _peer->m_totalDifficulty = maxDifficulty;
+ if (peerShouldGrabChain(_peer))
+ resetSyncTo(maxUnknown);
}
continueSync(_peer);
@@ -528,7 +539,7 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
{
RecursiveGuard l(x_sync);
DEV_INVARIANT_CHECK;
- if ((isSyncing() || _peer->isConversing()) && m_state != SyncState::NewBlocks)
+ if ((isSyncing() || _peer->isConversing()))
{
clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading.";
return;
@@ -565,11 +576,14 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
u256 difficulty = _r[1].toInt();
if (m_syncingTotalDifficulty < difficulty)
{
- clog(NetMessageSummary) << "Received block with no known parent. Resyncing...";
_peer->m_latestHash = h;
_peer->m_totalDifficulty = difficulty;
- resetSyncTo(h);;
- sync = true;
+ if (peerShouldGrabChain(_peer))
+ {
+ clog(NetMessageSummary) << "Received block with no known parent. Resyncing...";
+ resetSyncTo(h);;
+ sync = true;
+ }
}
}
break;
@@ -580,7 +594,7 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
_peer->m_knownBlocks.insert(h);
if (sync)
- continueSync();
+ continueSync(_peer);
}
DEV_INVARIANT_CHECK;
}
@@ -623,6 +637,7 @@ void EthereumHost::onPeerAborting(EthereumPeer* _peer)
_peer->setRude();
continueSync();
}
+ DEV_INVARIANT_CHECK;
}
void EthereumHost::continueSync()
@@ -758,10 +773,6 @@ bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const
bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const
{
- // Early exit if this peer has proved unreliable.
- if (_peer->isRude())
- return false;
-
h256 c = m_chain.currentHash();
unsigned n = m_chain.number();
u256 td = m_chain.details().totalDifficulty;
@@ -815,6 +826,5 @@ bool EthereumHost::invariants() const
return false;
if (needBlocks() && (m_syncingLatestHash || !m_hashes.empty()))
return false;
-
return true;
}
diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp
index b876bf019..4e6f7afca 100644
--- a/libethereum/EthereumPeer.cpp
+++ b/libethereum/EthereumPeer.cpp
@@ -106,6 +106,7 @@ void EthereumPeer::requestStatus()
{
assert(m_asking == Asking::Nothing);
setAsking(Asking::State);
+ m_requireTransactions = true;
RLPStream s;
bool latest = m_peerCapabilityVersion == host()->protocolVersion();
prep(s, StatusPacket, latest ? 6 : 5)
diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp
index 1e7766434..b50e316d3 100644
--- a/liblll/CodeFragment.cpp
+++ b/liblll/CodeFragment.cpp
@@ -196,7 +196,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
{
if (_t.size() != 2)
error();
- m_asm.append(CodeFragment::compile(asString(contents(firstAsString())), _s).m_asm);
+ m_asm.append(CodeFragment::compile(contentsString(firstAsString()), _s).m_asm);
}
else if (us == "SET")
{
diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp
index 1482719c6..a0d8e1297 100644
--- a/libp2p/Host.cpp
+++ b/libp2p/Host.cpp
@@ -326,7 +326,8 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
{
clog(NetP2PNote) << "p2p.host.nodeTable.events.NodeEntryDropped " << _n;
RecursiveGuard l(x_sessions);
- m_peers.erase(_n);
+ if (m_peers.count(_n) && !m_peers[_n]->required)
+ m_peers.erase(_n);
}
}
@@ -637,27 +638,40 @@ void Host::run(boost::system::error_code const&)
// updated. // disconnectLatePeers();
// todo: update peerSlotsAvailable()
- unsigned pendingCount = 0;
- DEV_GUARDED(x_pendingNodeConns)
- pendingCount = m_pendingPeerConns.size();
- int openSlots = m_idealPeerCount - peerCount() - pendingCount;
- if (openSlots > 0)
+
+ list> toConnect;
+ unsigned reqConn = 0;
{
- list> toConnect;
+ RecursiveGuard l(x_sessions);
+ for (auto const& p: m_peers)
{
- RecursiveGuard l(x_sessions);
- for (auto p: m_peers)
- if (p.second->shouldReconnect() && !havePeerSession(p.second->id))
- toConnect.push_back(p.second);
+ bool haveSession = havePeerSession(p.second->id);
+ bool required = p.second->required;
+ if (haveSession && required)
+ reqConn++;
+ else if (!haveSession && p.second->shouldReconnect() && (!m_netPrefs.pin || required))
+ toConnect.push_back(p.second);
}
+ }
+
+ for (auto p: toConnect)
+ if (p->required && reqConn++ < m_idealPeerCount)
+ connect(p);
+
+ if (!m_netPrefs.pin)
+ {
+ unsigned pendingCount = 0;
+ DEV_GUARDED(x_pendingNodeConns)
+ pendingCount = m_pendingPeerConns.size();
+ int openSlots = m_idealPeerCount - peerCount() - pendingCount + reqConn;
+ if (openSlots > 0)
+ {
+ for (auto p: toConnect)
+ if (!p->required && openSlots--)
+ connect(p);
- for (auto p: toConnect)
- if (openSlots--)
- connect(p);
- else
- break;
-
- m_nodeTable->discover();
+ m_nodeTable->discover();
+ }
}
auto runcb = [this](boost::system::error_code const& error) { run(error); };
@@ -698,7 +712,7 @@ void Host::startedWorking()
else
clog(NetP2PNote) << "p2p.start.notice id:" << id() << "TCP Listen port is invalid or unavailable.";
- shared_ptr nodeTable(new NodeTable(m_ioService, m_alias, NodeIPEndpoint(bi::address::from_string(listenAddress()), listenPort(), listenPort())));
+ shared_ptr nodeTable(new NodeTable(m_ioService, m_alias, NodeIPEndpoint(bi::address::from_string(listenAddress()), listenPort(), listenPort()), m_netPrefs.discovery));
nodeTable->setEventHandler(new HostNodeTableHandler(*this));
m_nodeTable = nodeTable;
restoreNetwork(&m_restoreNetwork);
diff --git a/libp2p/Network.h b/libp2p/Network.h
index d02ce3cbe..e70dd89ea 100644
--- a/libp2p/Network.h
+++ b/libp2p/Network.h
@@ -52,6 +52,8 @@ struct NetworkPreferences
std::string listenIPAddress;
unsigned short listenPort = 30303;
bool traverseNAT = true;
+ bool discovery = true; // Discovery is activated with network.
+ bool pin = false; // Only connect to trusted ("required") peers.
};
/**
diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp
index 6344dc263..1a0b11734 100644
--- a/libp2p/NodeTable.cpp
+++ b/libp2p/NodeTable.cpp
@@ -40,14 +40,15 @@ const char* NodeTableIngress::name() { return "<connect();
- doRefreshBuckets(boost::system::error_code());
+ if (!m_disabled)
+ {
+ m_socketPointer->connect();
+ doRefreshBuckets(boost::system::error_code());
+ }
}
NodeTable::~NodeTable()
diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h
index 0ec13c828..d31a356ef 100644
--- a/libp2p/NodeTable.h
+++ b/libp2p/NodeTable.h
@@ -130,7 +130,7 @@ public:
enum NodeRelation { Unknown = 0, Known };
/// Constructor requiring host for I/O, credentials, and IP Address and port to listen on.
- NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint);
+ NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint, bool _enabled = true);
~NodeTable();
/// Returns distance based on xor metric two node ids. Used by NodeEntry and NodeTable.
@@ -271,6 +271,8 @@ private:
boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh.
boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions.
+
+ bool m_disabled; ///< Disable discovery.
};
inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable)
diff --git a/libp2p/Peer.cpp b/libp2p/Peer.cpp
index 6f368a4b4..a8b4a993d 100644
--- a/libp2p/Peer.cpp
+++ b/libp2p/Peer.cpp
@@ -38,6 +38,8 @@ bool Peer::shouldReconnect() const
unsigned Peer::fallbackSeconds() const
{
+ if (required)
+ return 5;
switch (m_lastDisconnect)
{
case BadProtocol:
diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp
index b55ae7d36..82e98dfff 100644
--- a/libsolidity/Compiler.cpp
+++ b/libsolidity/Compiler.cpp
@@ -30,9 +30,8 @@
#include
using namespace std;
-
-namespace dev {
-namespace solidity {
+using namespace dev;
+using namespace dev::solidity;
/**
* Simple helper class to ensure that the stack height is the same at certain places in the code.
@@ -301,24 +300,18 @@ void Compiler::appendCalldataUnpacker(
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)
{
- unsigned dataOffset = 0;
- unsigned stackDepth = 0;
- for (TypePointer const& type: _typeParameters)
- stackDepth += type->getSizeOnStack();
-
- for (TypePointer const& type: _typeParameters)
- {
- CompilerUtils(m_context).copyToStackTop(stackDepth, type->getSizeOnStack());
- ExpressionCompiler(m_context, m_optimize).appendTypeConversion(*type, *type, true);
- bool const c_padToWords = true;
- dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, *type, c_padToWords);
- stackDepth -= type->getSizeOnStack();
- }
- // note that the stack is not cleaned up here
- if (dataOffset == 0)
+ CompilerUtils utils(m_context);
+ if (_typeParameters.empty())
m_context << eth::Instruction::STOP;
else
- m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN;
+ {
+ utils.fetchFreeMemoryPointer();
+ //@todo optimization: if we return a single memory array, there should be enough space before
+ // its data to add the needed parts and we avoid a memory copy.
+ utils.encodeToMemory(_typeParameters, _typeParameters);
+ utils.toSizeAfterFreeMemoryPointer();
+ m_context << eth::Instruction::RETURN;
+ }
}
void Compiler::registerStateVariables(ContractDefinition const& _contract)
@@ -634,8 +627,5 @@ void Compiler::compileExpression(Expression const& _expression, TypePointer cons
ExpressionCompiler expressionCompiler(m_context, m_optimize);
expressionCompiler.compile(_expression);
if (_targetType)
- expressionCompiler.appendTypeConversion(*_expression.getType(), *_targetType);
-}
-
-}
+ CompilerUtils(m_context).convertType(*_expression.getType(), *_targetType);
}
diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp
index 7a96db928..349877a29 100644
--- a/libsolidity/CompilerUtils.cpp
+++ b/libsolidity/CompilerUtils.cpp
@@ -23,6 +23,8 @@
#include
#include
#include
+#include
+#include
using namespace std;
@@ -33,6 +35,7 @@ namespace solidity
const unsigned CompilerUtils::dataStartOffset = 4;
const size_t CompilerUtils::freeMemoryPointer = 64;
+const unsigned CompilerUtils::identityContractAddress = 4;
void CompilerUtils::initialiseFreeMemoryPointer()
{
@@ -83,8 +86,7 @@ void CompilerUtils::loadFromMemoryDynamic(
if (_keepUpdatedMemoryOffset)
{
// update memory counter
- for (unsigned i = 0; i < _type.getSizeOnStack(); ++i)
- m_context << eth::swapInstruction(1 + i);
+ moveToStackTop(_type.getSizeOnStack());
m_context << u256(numBytes) << eth::Instruction::ADD;
}
}
@@ -108,15 +110,80 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
if (type.location() == ReferenceType::Location::CallData)
{
// stack: target source_offset source_len
- m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5
+ m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5;
// stack: target source_offset source_len source_len source_offset target
- << eth::Instruction::CALLDATACOPY
- << eth::Instruction::DUP3 << eth::Instruction::ADD
- << eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP;
+ m_context << eth::Instruction::CALLDATACOPY;
+ m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
+ m_context << eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP;
+ }
+ else if (type.location() == ReferenceType::Location::Memory)
+ {
+ // memcpy using the built-in contract
+ ArrayUtils(m_context).retrieveLength(type);
+ if (type.isDynamicallySized())
+ {
+ // change pointer to data part
+ m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD;
+ m_context << eth::Instruction::SWAP1;
+ }
+ // stack: