add plugin transaction

自分のためのメモ
ほぼこれのコピー
指定したアカウントからモザイクを盗み出すトランザクション

https://qiita.com/monakaJP/items/1f1fdea9aec0980f0466

``` client/catapult/plugins/txes/transfer/src/model/StealTransaction.h
#pragma once
#include "TransferEntityType.h"
#include "catapult/model/Mosaic.h"
#include "catapult/model/Transaction.h"

namespace catapult { namespace model {

#pragma pack(push, 1)

	/// Binary layout for a steal transaction body.
	template<typename THeader>
	struct StealTransactionBody : public THeader {
	private:
		using TransactionType = StealTransactionBody<THeader>;

	public:
		DEFINE_TRANSACTION_CONSTANTS(Entity_Type_Steal, 1)

	public:
		/// Recipient address.
		UnresolvedAddress RecipientAddress;

		/// Message size in bytes.
		uint16_t MessageSize;

		/// Number of mosaics.
		uint8_t MosaicsCount;

		/// Reserved padding to align Mosaics on 8-byte boundary.
		uint32_t TransferTransactionBody_Reserved1;
		uint8_t TransferTransactionBody_Reserved2;

		// followed by mosaics data if MosaicsCount != 0
		DEFINE_TRANSACTION_VARIABLE_DATA_ACCESSORS(Mosaics, UnresolvedMosaic)

		// followed by message data if MessageSize != 0
		DEFINE_TRANSACTION_VARIABLE_DATA_ACCESSORS(Message, uint8_t)

	private:
		template<typename T>
		static auto* MosaicsPtrT(T& transaction) {
			return transaction.MosaicsCount ? THeader::PayloadStart(transaction) : nullptr;
		}

		template<typename T>
		static auto* MessagePtrT(T& transaction) {
			auto* pPayloadStart = THeader::PayloadStart(transaction);
			return transaction.MessageSize && pPayloadStart
					? pPayloadStart + transaction.MosaicsCount * sizeof(UnresolvedMosaic)
					: nullptr;
		}

	public:
		/// Calculates the real size of steal \a transaction.
		static constexpr uint64_t CalculateRealSize(const TransactionType& transaction) noexcept {
			return sizeof(TransactionType) + transaction.MessageSize + transaction.MosaicsCount * sizeof(UnresolvedMosaic);
		}
	};

	DEFINE_EMBEDDABLE_TRANSACTION(Steal)

#pragma pack(pop)
}}
```


``` client/catapult/plugins/txes/transfer/src/model/TransferEntityType.h
	/// Transfer transaction.
	DEFINE_TRANSACTION_TYPE(Transfer, Transfer, 0x1);

+	DEFINE_TRANSACTION_TYPE(Transfer, Steal, 0x2);
```

``` client/catapult/plugins/txes/transfer/src/plugins/StealTransactionPlugin.cpp
#include "StealTransactionPlugin.h"
#include "src/model/TransferNotifications.h"
#include "src/model/StealTransaction.h"
#include "catapult/model/NotificationSubscriber.h"
#include "catapult/model/TransactionPluginFactory.h"

using namespace catapult::model;

namespace catapult { namespace plugins {

	namespace {
		template<typename TTransaction>
		void Publish(const TTransaction& transaction, const PublishContext& context, NotificationSubscriber& sub) {
			auto padding = transaction.TransferTransactionBody_Reserved1 << 8 | transaction.TransferTransactionBody_Reserved2;
			sub.notify(InternalPaddingNotification(padding));
			sub.notify(AccountAddressNotification(transaction.RecipientAddress));
			sub.notify(AddressInteractionNotification(context.SignerAddress, transaction.Type, { transaction.RecipientAddress }));

			const auto* pMosaics = transaction.MosaicsPtr();
			for (auto i = 0u; i < transaction.MosaicsCount; ++i) {
				sub.notify(BalanceTransferNotification(
						transaction.RecipientAddress,
						context.SignerAddress,
						pMosaics[i].MosaicId,
						pMosaics[i].Amount));
			}

			if (transaction.MessageSize) {
				sub.notify(TransferMessageNotification(
						transaction.SignerPublicKey,
						transaction.RecipientAddress,
						transaction.MessageSize,
						transaction.MessagePtr()));
			}

			if (transaction.MosaicsCount)
				sub.notify(TransferMosaicsNotification(transaction.MosaicsCount, pMosaics));
		}
	}

	DEFINE_TRANSACTION_PLUGIN_FACTORY(Steal, Default, Publish)
}}

```

``` client/catapult/plugins/txes/transfer/src/plugins/StealTransactionPlugin.h
#pragma once
#include "catapult/plugins.h"
#include <memory>

namespace catapult { namespace model { class TransactionPlugin; } }

namespace catapult { namespace plugins {

	/// Creates a transfer transaction plugin.
	PLUGIN_API
	std::unique_ptr<model::TransactionPlugin> CreateStealTransactionPlugin();
}}
```

``` client/catapult/plugins/txes/transfer/src/plugins/TransferPlugin.cpp
#include "catapult/plugins/PluginManager.h"
+ #include "StealTransactionPlugin.h"
...
manager.addTransactionSupport(CreateTransferTransactionPlugin());
+ manager.addTransactionSupport(CreateStealTransactionPlugin());
```

## Mongo
``` /symbol/client/catapult/extensions/mongo/plugins/transfer/src/MongoTransferPlugin.cpp
void RegisterMongoSubsystem(catapult::mongo::MongoPluginManager& manager) {
	manager.addTransactionSupport(catapult::mongo::plugins::CreateTransferTransactionMongoPlugin());
	+ manager.addTransactionSupport(catapult::mongo::plugins::CreateStealTransactionMongoPlugin());
}

```
``` /symbol/client/catapult/extensions/mongo/plugins/transfer/src/TransferMapper.cpp
#include "plugins/txes/transfer/src/model/TransferTransaction.h"
+ #include "plugins/txes/transfer/src/model/StealTransaction.h"

DEFINE_MONGO_TRANSACTION_PLUGIN_FACTORY(Transfer, StreamTransaction)
+ DEFINE_MONGO_TRANSACTION_PLUGIN_FACTORY(Steal, StreamTransaction)
```

``` /symbol/client/catapult/extensions/mongo/plugins/transfer/src/TransferMapper.h
PLUGIN_API
std::unique_ptr<MongoTransactionPlugin> CreateTransferTransactionMongoPlugin();
+ std::unique_ptr<MongoTransactionPlugin> CreateStealTransactionMongoPlugin();
```

## build

```
BOOST_ROOT="$(realpath ../_deps/boost)" cmake .. \
	-DENABLE_TESTS=OFF \
	-DCMAKE_BUILD_TYPE=RelWithDebInfo \
	-DCMAKE_PREFIX_PATH="$(realpath ../_deps/facebook);$(realpath ../_deps/google);$(realpath ../_deps/mongodb);$(realpath ../_deps/zeromq)" \
	-GNinja
```

```
ninja publish
```

```
ninja
```

## sdk
``` catbuffer/schemas/symbol/transfer/steal.cats
import "transaction.cats"

# Shared content between StealTransactionBody and EmbeddedStealTransactionBody.
inline struct StealTransactionBody
	# recipient address
	recipient_address = UnresolvedAddress

	# size of attached message
	message_size = uint16

	# number of attached mosaics
	mosaics_count = uint8

	# reserved padding to align mosaics on 8-byte boundary
	steal_transaction_body_reserved_1 = make_reserved(uint8, 0)

	# reserved padding to align mosaics on 8-byte boundary
	steal_transaction_body_reserved_2 = make_reserved(uint32, 0)

	# attached mosaics
	@sort_key(mosaic_id)
	mosaics = array(UnresolvedMosaic, mosaics_count)

	# attached message
	message = array(uint8, message_size)

# Send mosaics and messages between two accounts (V1, latest).
struct StealTransactionV1
	TRANSACTION_VERSION = make_const(uint8, 1)
	TRANSACTION_TYPE = make_const(TransactionType, STEAL)

	inline Transaction
	inline StealTransactionBody

# Embedded version of TransferTransaction (V1, latest).
struct EmbeddedStealTransactionV1
	TRANSACTION_VERSION = make_const(uint8, 1)
	TRANSACTION_TYPE = make_const(TransactionType, STEAL)

	inline EmbeddedTransaction
	inline StealTransactionBody
```

``` catbuffer/schemas/symbol/all_transactions.cats
import "transfer/transfer.cats"
+ import "transfer/steal.cats"
```

``` catbuffer/schemas/symbol/transaction_type.cats
	# TransferTransaction
	TRANSFER = 0x4154
	
	+ # StealTransaction
    + STEAL = 0x4254
```

## build
```
./scripts/run_catbuffer_generator.sh
```

## StealTest
``` c#
var tx = new StealTransactionV1()
{
    Network = NetworkType.TESTNET,
    SignerPublicKey = bob.PublicKey,
    Deadline = new Timestamp(facade.Network.FromDatetime<NetworkTimestamp>(DateTime.UtcNow).AddHours(2).Timestamp),
    RecipientAddress = new UnresolvedAddress(facade.Network.PublicKeyToAddress(alice.PublicKey.bytes).bytes),
    Mosaics = new UnresolvedMosaic[]
    {
        new UnresolvedMosaic()
        {
            MosaicId = new UnresolvedMosaicId(0x382C1EA7C524D2E8),
            Amount = new Amount(100)
        }
    }
};
```