Краткий анализ протокола <Loopring--Loopring> и общий анализ исходного кода Relay

задняя часть база данных Go исходный код блокчейн
Краткий анализ протокола <Loopring--Loopring> и общий анализ исходного кода Relay

Автор: Линь Гуаньхун / Призраки под рукой

пролог:

路印协议Функции очень многочисленны и мощны, и в этой статье проводится только анализ начального уровня.

Для теоретической части, пожалуйста, внимательно прочитайте его технический документ.GitHub.com/loop ring/ Я тоже…

Фактическая часть кода:GitHub.com/кольцо цикла/горячее…


содержание

  • Протокол закольцовывания
  • обычно используется в
  • эффект
  • компоненты модуля
  • Процесс сделки
  • Код основной бизнес-логики
  • relayОбзор исходного кода

路印协议

  • короткое имяLoopring
  • и0x,KyberТо же самое, это блокчейн-приложение去中心化交易协议Во-первых, в соглашении уточняется, что поведение при его использовании для проведения сделок купли-продажи должно осуществляться в соответствии с предусмотренным им режимом.
  • Описанный с процессуальной точки зрения, этоGo语言Написанное программное обеспечение с открытым исходным кодом, которое можно применять к блокчейну.
  • Также обратите внимание, что его нет в блокчейн-приложениях.智能合约, читатель обращает внимание на различие этих двух понятий.

обычно используется в

  • обмен виртуальной валюты,交易所Есть следующие примеры
    • MtGox
    • Bitfinex
    • Хуоби
    • OKEX
    • ...

эффект

  • Решить ряд проблем, существующих в централизованной торговле
    • отсутствие безопасности
      • Биржа сохраняет закрытый ключ пользователя, который был украден после хакерской атаки.
      • Для проявления требуется одобрение биржи.Представьте, если бы сотрудники биржи сбежали с деньгами или вдруг закрылись
    • отсутствие прозрачности
      • Покупка и продажа пользователей заменены централизованными биржами, а внутренние специфические процессы держатся в секрете.
      • Пользовательские активы могут быть использованы в качестве сторонних инвестиций
    • отсутствие ликвидности
      • Биржи с большим объемом торгов могут стать монополистами рынка.
      • Даже после серьезной аварии другим пользователям приходится продолжать торговать на бирже из-за их огромной доли рынка.
  • Некоторые проблемы оптимизации существующих транзакций диалекта районного центра
    • отсутствие единых стандартов
    • плохая ликвидность
      • Сеть вещания малых заказов
      • Скорость обновления таблицы заказов низкая после завершения транзакции
    • проблемы с производительностью
      • Вызывает высокую комиссию за выполнение кода
      • задержка питтинга
      • Изменение/отмена заказов стоит дорого

компоненты модуля

  • Программное обеспечение кошелька, поддерживающее отправку запросов в сеть Loopring.
    • APP
    • WEB
  • Программное обеспечение Loopring Relay --Relay
  • Циклический смарт-контракт блокчейна --LPSC
  • Релейная сеть Loopring, управляемая несколькими路印中继软件сетевых узлов
  • Цепочка альянсов Loopring, организованнаяLPSCблокчейн

Процесс сделки

Сравните картинку выше с 6 шагами.说明и代码核心业务逻辑

1. Авторизация соглашения

  • Пользователь Y хочет торговать токенами, поэтому разрешает LPSC продать 9 токенов B. Это действие не замораживает токены пользователя. Во время обработки заказа пользователи по-прежнему могут свободно распоряжаться токенами.
  • 代码调用逻辑Да: кошелек для определенного блокчейна, такого как Ethereum.公有链положить началоjson-rpc请求, по запросу合约地址addressи合约ABIПосле того, как информация находит соответствующий контракт LPSC,methodNameНайдите соответствующие методы интерфейса, которые, конечно же, соответствуют стандарту ERC20. Запросить авторизацию на продажу 9 токенов B для учетной записи Y.

2. Создание заказа

  • В приложении кошелька или веб-приложении он отображается сетевым посредником, таким как сторонний интерфейс API.https://api.coinmarketcap.comпоставка Текущий обменный курс и таблица ордеров между токеном B и токеном C. Основываясь на этой информации, пользователи настраивают свои собственные покупки и продажи токенов и связанные с ними количества, например: продажа10ETH,Купить50EOS. Затем создайте этот запрос заказа с дополнительной информацией в заказе. Окончательный заказ шифруется закрытым ключом пользователя Y, то есть подписывается и отправляется中继点软件 --- relay

  • 代码调用逻辑Да: клиент кошелька может использовать Http-запрос для вызова стороннего API-интерфейса или использовать другие методы для полученияticker--24小时市场变化统计数据После объединения с информацией о цене каждого токена таблица заказов и обменный курс отображаются в сочетании через интерфейс пользовательского интерфейса. После того, как пользователь настроил свою собственную информацию о заказе и подписалjosn-rpcзапроситьrelayИнициировать запрос заказа.

  • Этапы подписания заказа

    • Документация
    • использоватьKeccak-256Алгоритм хеширует этот массив байтов, чтобы получить хэш порядка
    • Алгоритм подписи Secp256k1 подписывает полученный хеш, чтобы получить Sig.
    • 0–32 бита Sig преобразуются в шестнадцатеричные строки и присваиваются r порядка.
    • 32-64 бита Sig преобразуются в шестнадцатеричные строки и присваиваются s of Order.
    • 64 бита Sig плюс 27 преобразуются в v целочисленного порядка.

3. Заказать трансляцию

  • Кошелек отправляет ордер и его подпись на один или несколько ретрансляторов, а ретранслятор затем обновляет свою таблицу публичных ордеров. Протокол Loopring не ограничивает структуру таблицы заказов, допуская модель «первым пришел, первым обслужен»; ретранслятор может сам выбирать структуру таблицы заказов.

  • 代码调用逻辑Да: клиент отправляет один или несколькоrelayОтправитьorder requestЗадний,relayПосле получения заказа, а затем друг к другуrelayВещание, технический пункт вещанияrelayв исходном кодеgatewayЧасть его можно увидеть с помощьюIPFS--点对点的分布式版本文件系统Технологии. то этиrelayНажмите на них, чтобы составить то, что сказано выше路印中继网. Затем каждыйrelayСделать соответствующие формы заказаrefresh, что обеспечивает единство. Дизайн таблицы настраивается, например, поля, выбор механизма базы данных и т. д.

4. Разделение ликвидности

  • Эта часть была подчинена Межвещательной части третьего пункта.
  • Кроме того, два дополнительных пункта
    • Узлы имеют право выбирать, взаимодействовать ли и каким образом, и мы можем вводить различные ограничения, изменяя исходный код.
    • В этой части есть ключевой момент - проектирование алгоритма обновления таблицы после приема трансляции, как добиться高速处理и杜绝误差回滚

5. Сопоставление цикла (сопоставление порядка)

  • Кольцевые майнеры сопоставляют несколько заказов и удовлетворяют часть или всю сумму заказа по обменному курсу, равному или лучше, чем обменный курс, указанный пользователем. Причина, по которой Loopring может гарантировать высокую ликвидность между любой торговой парой, во многом связана с Ring Miners. Если скорость транзакции выше, чем ставка пользователя Y, все заказы в цикле могут разделить прибыль. В качестве вознаграждения кольцевые майнеры могут собирать часть прибыли (разделять прибыль и одновременно платить LRx пользователю) или взимать первоначальную комиссию LRx.

  • Первоначальная платаLRxзадается клиентом при создании заказа

  • Математический символ петли

    • 环路矿工撮合多笔订单,以等同或优于用户开出的汇率满足部分或全部订单数额. Его выражение: Ri->j * Rj->i >= 1
    • Кроме того, по определенному ордеру торгуется его часть. Например, если вы продаете 10А, чтобы купить 2В, и вы продаете 4А, то по умолчанию должна быть покупка (2/5)В. так как. Курс обмена заказа постоянный Если ордер не исполнен полностью: Ri->j * Rj->i = 1, пропорциональный курс для частичной продажи и покупки равен原始的兑换率. 10/2=4/год
  • 代码调用逻辑Да:minerчасть кода иrelayв том же проекте. существуетrelayПосле обработки заказа,minerЯ перейду к форме заказа, чтобы получить заказ на соответствие. Сформировано оптимальное кольцо, т. е. порядок успешно подобран,minerЭтот слой будет выполнять соответствующие математические операции.

6. Проверка и расчет

  • Эта частьLPSCобработанный.
    • После того, как LPSC получает кольцо заказов, он выполняет несколько проверок для проверки данных, предоставленных майнерами кольца, таких как подписи всех сторон.
    • Определяет, может ли кольцо ордера быть частично или полностью рассчитано (в зависимости от обменного курса кольца ордера и баланса токенов в кошельке пользователя).
    • Если проверки соответствуют стандартам, LPSC пройдет原子操作Токены передаются пользователям, а комиссионные выплачиваются кольцевым майнерам и кошелькам.
    • Если LPSC обнаружит, что баланс пользователя Y недостаточен, он уменьшит сумму заказа.
    • Как только на адрес будет зачислено достаточно средств, заказ автоматически вернется к первоначальной сумме. Отмена заказа требует односторонней ручной операции и необратима.
    • Адрес в указанном выше адресе депозита относится к адресу учетной записи пользователя в блокчейне.
  • 代码调用逻辑Да:relayПучокminerДанные цикла , как и в первом пункте, передаются черезjson-rpcзапрос в публичную сетьLPSCдоговор и пусть он обрабатывается.

relayОбзор исходного кода

Насколько я проанализировал последниеrelayисходный код, который внутренне в настоящее время основан наETHПубличная сеть как первая блокчейн-платформа для разработки. внутреннее использование以太坊В исходном пакете Go есть множество структур методов,json-rpcНаиболее часто вызываемые команды:Gethиз.

Возможно, учитывая зрелость и популярность ETH, ETH был выбран в качестве первой платформы блокчейна для разработки. Но протокол Loopring не предназначен для ETH, его можно реализовать на нескольких разнородных блокчейнах, соответствующих условиям. Последующие оценки будут учитывать развитие общедоступных сетей, таких как EOS и ETC.

запись программы

Принят режим cli, то есть предусмотрен локальный запрос командной строки. Также предоставляются внешние API.

--relay
--|--cmd
--|--|--lrc
--|--|--|--main.go

func main() {
    app := utils.NewApp()
    app.Action = startNode // 启动一个中继节点
    ...
}

Инициализация и запуск узла

func startNode(ctx *cli.Context) error {

	globalConfig := utils.SetGlobalConfig(ctx) // 读取配置文件并初始化
	// 日志系统初始化
	// 对系统中断和程序被杀死事件信号的注册
	n = node.NewNode(logger, globalConfig) // 初始化节点
	//...
	n.Start() // 启动节点
	//...
	return nil
}

Файл конфигурации находится по адресу

--relay
--|--config
--|--|--relay.toml
--|--|--其它

relay.tomlСуществует множество внутренних настраиваемых элементов, таких как база данных жесткого хранилища.MySQLНастройки информации о конфигурации и т. д.

Инициализируйте узел, см. комментарии к следующему коду для введения каждой части

func NewNode(logger *zap.Logger, globalConfig *config.GlobalConfig) *Node {
    // ...
    // register
    n.registerMysql() // lgh:初始化数据库引擎句柄和创建对应的表格,使用了 gorm 框架
    cache.NewCache(n.globalConfig.Redis) // lgh:初始化Redis,内存存储三方框架
    
    util.Initialize(n.globalConfig.Market) // lgh:设置从 json 文件导入代币信息,和市场
    n.registerMarketCap() // lgh: 初始化货币市值信息,去网络同步
    
    n.registerAccessor()  // lgh: 初始化指定合约的ABI和通过json-rpc请求eth_call去以太坊获取它们的地址,以及启动了定时任务同步本地区块数目,仅数目
    
    n.registerUserManager() // lgh: 初始化用户白名单相关操作,内存缓存部分基于 go-cache 库,以及启动了定时任务更新白名单列表
    
    n.registerOrderManager() // lgh: 初始化订单相关配置,含内存缓存-redis,以及系列的订单事件监听者,如cancel,submit,newOrder 等
    n.registerAccountManager() // lgh: 初始化账号管理实例的一些简单参数。内部主要是和订单管理者一样,拥有用户交易动作事件监听者,例如转账,确认等
    n.registerGateway() // lgh:初始化了系列的过滤规则,包含订单请求规则等。以及 GatewayNewOrder 新订单事件的订阅
    n.registerCrypto(nil) // lgh: 初始化加密器,目前主要是Keccak-256
    
    if "relay" == globalConfig.Mode {
    	n.registerRelayNode()
    } else if "miner" == globalConfig.Mode {
    	n.registerMineNode()
    } else {
    	n.registerMineNode()
    	n.registerRelayNode()
    }
    
    return n
}

func (n *Node) registerRelayNode() {
    n.relayNode = &RelayNode{}
    n.registerExtractor()
    n.registerTransactionManager() // lgh:事务管理器
    n.registerTrendManager()   // lgh: 趋势数据管理器,市场变化趋势信息
    n.registerTickerCollector() // lgh: 负责统计24小时市场变化统计数据。目前支持的平台有OKEX,币安
    n.registerWalletService() // lgh: 初始化钱包服务实例
    n.registerJsonRpcService()// lgh: 初始化 json-rpc 端口和绑定钱包WalletServiceHandler,start 的时候启动服务
    n.registerWebsocketService() // lgh: 初始化 webSocket
    n.registerSocketIOService()
    txmanager.NewTxView(n.rdsService)
}

func (n *Node) registerMineNode() {
    n.mineNode = &MineNode{}
    ks := keystore.NewKeyStore(n.globalConfig.Keystore.Keydir, keystore.StandardScryptN, keystore.StandardScryptP)
    n.registerCrypto(ks)
    n.registerMiner()
}

из вышеперечисленногоregisterНажмите, чтобы начать анализ. Есть следующие выводы

  • Общий,relayРежим связи внутреннего кода основан на:事件订阅--事件接收--事件处理из.
  • relayВ качестве базы данных жесткого хранилища используется распределенная база данных Mysql, которая используется в коде.gormРамка. существуетregisterMysqlСозданные формы и т.д.
  • Есть два набора памяти
    • на основеRedis
    • на основеgo-cacheбиблиотека
  • В информации об импортном токене и в разделе информации о рыночной стоимости есть问题点: в файле конфигурации市场市值Сторонний интерфейс для сбора данныхcoinmarketcapопубликовала заявление на своем официальном сайте,v1Версия API будет отключена 30 ноября этого года, так что,relayСледующее в файле конфигурации по умолчанию здесь необходимо изменить наv2версия.

[market_cap]
        base_url = "https://api.coinmarketcap.com/v1/ticker/?limit=0&convert=%s"
        currency = "USD"
        duration = 5
        is_sync = false
  • OrderManagerиAccountManagerзарегистрирован вEventсобытие, точка, которая в основном срабатывает,socketio.go, соответствующий упомянутому вышеgatewayмодуль, отвечающий за получениеIPFSтрансляция сообщений. После того, как он будет получен, он будет снова передан для запуска обработки события.

    --relay
    --|--gateway
    --|--|--socketio.go
    
    func (so *SocketIOServiceImpl) broadcastTrades(input eventemitter.EventData) (err error) {
        // ...
        v.Emit(eventKeyTrades+EventPostfixRes, respMap[fillKey])
        // ...
    }
    
  • Шаги запуска события нового заказа разделены на два уровня.

    • gateway.goвнутриeventemitter.GatewayNewOrderЗависит отIPFSраспределение
    • OrderManagerвнутриeventemitter.NewOrder
      • Зависит отgateway.goполучилаGatewayNewOrderраспространен позже.
      • Звонок клиентаWalletServiceAPISubmitOrderпост-триггер
  • relayиз节点模式Есть 3 вида

    • одиночный запускrelayузел ретрансляции

    • одиночный запускminerузел майнера

    • Двойная загрузка, которая является формой по умолчанию

      if "relay" == globalConfig.Mode {
      	n.registerRelayNode()
      } else if "miner" == globalConfig.Mode {
      	n.registerMineNode()
      } else {
      	n.registerMineNode()
      	n.registerRelayNode()
      }
      
  • relay--中继节点API, предоставляемый клиенту, в основномWalletServiceкошелек. Имя префиксного метода:loopring

    • Поддержка вызова формата json-rpc

    • Просто позвоните в форме Http-GET & POST

      func (j *JsonrpcServiceImpl) Start() {
          handler := rpc.NewServer()
          if err := handler.RegisterName("loopring", j.walletService); err != nil {
          	fmt.Println(err)
          	return
          }
          var (
          	listener net.Listener
          	err      error
          )
          if listener, err = net.Listen("tcp", ":"+j.port); err != nil {
          	return
          }
          //httpServer := rpc.NewHTTPServer([]string{"*"}, handler)
          httpServer := &http.Server{Handler: newCorsHandler(handler, []string{"*"})}
          //httpServer.Handler = newCorsHandler(handler, []string{"*"})
          go httpServer.Serve(listener)
          log.Info(fmt.Sprintf("HTTP endpoint opened on " + j.port))
          return
      }
      
  • Miner--矿工节点, в основном обеспечивает функцию сопоставления циклов заказов, которую можно настроить с помощью следующих частей.

    [miner]
        ringMaxLength = 4  // 最大的环个数
        name = "miner1"
        rate_ratio_cvs_threshold = 1000000000000000
        subsidy = 1.0
        walletSplit = 0.8
        minGasLimit = 1000000000
        maxGasLimit = 100000000000 // 邮费最大值
        feeReceipt = "0x750aD4351bB728ceC7d639A9511F9D6488f1E259"
        [[miner.normal_miners]]
            address = "0x750aD4351bB728ceC7d639A9511F9D6488f1E259"
            maxPendingTtl = 40
            maxPendingCount = 20
            gasPriceLimit = 10000000000
        [miner.TimingMatcher]
        		round_orders_count=2
        		duration = 10000  // 触发一次撮合动作的毫秒数
        		delayed_number = 10000
        		max_cache_rounds_length = 1000
        		lag_for_clean_submit_cache_blocks = 200
        		reserved_submit_time = 45
        		max_sumit_failed_count = 3
    
    • Запуск узла майнера делится на две части:

      • Сопоставитель, отвечающий за сопоставление заказов
      • Отправитель, ответственный за отправку и другую обработку результатов заказа
      func (minerInstance *Miner) Start() {
          minerInstance.matcher.Start()
          minerInstance.submitter.start()
      }
      
    • minerсобственный计费者. существует匹配者matcherВремя отordermanagerВытащить n предметов изorderДанные сопоставляются в цикле, и если он зациклен, он вызывается вызовомevaluatorРассчитать стоимость и отправитьsubmitterСделать коммит в Ethereum

      evaluator := miner.NewEvaluator(n.marketCapProvider, n.globalConfig.Miner)
      
    • сопоставительmatcher.Start()

      func (matcher *TimingMatcher) Start() {
      	matcher.listenSubmitEvent() // lgh: 注册且监听 Miner_RingSubmitResult 事件,提交成功或失败或unknown 后,都从内存缓存中删除该环
      	matcher.listenOrderReady() // lgh: 定时器,每隔十秒,进行以太坊,即Geth同步的区块数和 relay 本地数据库fork是false的区块数进行对比,来控制匹配这 matcher 是否准备好,能够进行匹配
      	matcher.listenTimingRound() // lgh: 开始定时进行环的撮合,受上面的 orderReady 影响
      	matcher.cleanMissedCache() // lgh: 清除上一次程序退出前的错误内存缓存
      }
      
      • Gethколичество синхронизированных блоков иrelayлокальная база данныхfork是falseколичество блоков для сравнения
      if err = ethaccessor.BlockNumber(&ethBlockNumber); nil == err {
      	var block *dao.Block
      	// s.db.Order("create_time desc").Where("fork = ?", false).First(&block).Error
      	if block, err = matcher.db.FindLatestBlock(); nil == err { block.BlockNumber, ethBlockNumber.Int64())
      		if ethBlockNumber.Int64() > (block.BlockNumber + matcher.lagBlocks) {
      			matcher.isOrdersReady = false
      		} else {
      			matcher.isOrdersReady = true
      		}
      	}
      }
      ...
      
      • matcher.isOrdersReadyконтроль撮合的开始
      if !matcher.isOrdersReady {
      	return
      }
      ...
      m.match()
      ...
      
      • TimingMatcher.matchметод в целом订单撮合Основной. После успешного сопоставления он отправитeventemitter.Miner_NewRingНовое событие на ринге, расскажите подписчикам, что матч прошел успешно
    • Представленныйsubmitter.start(). Отправитель, есть очень важный шаг: после подписки и прослушиванияMiner_NewRingсобытие, то提交到以太坊, а затем обновите локальный环数据表. код показывает, как показано ниже

      // listenNewRings()
      txHash, status, err1 := submitter.submitRing(ringState) // 提交到以太坊
      ...
      submitter.submitResult(...) // 触发本地的 update
      
      func (submitter *RingSubmitter) submitRing(...) {
      	...
      	if nil == err {
      		txHashStr := "0x"
      		//  ethaccessor.SignAndSendTransaction 提交函数
      		txHashStr, err = ethaccessor.SignAndSendTransaction(ringSubmitInfo.Miner, ringSubmitInfo.ProtocolAddress, ringSubmitInfo.ProtocolGas, ringSubmitInfo.ProtocolGasPrice, nil, ringSubmitInfo.ProtocolData, false)
      		...
      		txHash = common.HexToHash(txHashStr)
      	} 
      	...
      }
      

На данный момент у нас есть общая концепция. по сравнению с вышеперечисленным交易流程рисунок. Чтобы инициировать заказ от клиента, обаrelayПосле обработки он, наконец, отправляется в блокчейн (например, в публичную сеть Ethereum) до тех пор, пока не будет завершена окончательная транзакция.relayКаждый модуль в исходном коде отвечает за свою собственную ответственность.

Relayда钱包и路印协议между桥接, вверх и钱包приклад, вниз иMinerстыковка. давать钱包предоставить API дляMinerОбеспечить заказы, поддерживать пул заказов внутри.

minerСоответствие заказов с одной стороны, а с другой стороныLPSCвзаимодействовать. иLPSCОн взаимодействует с публичной сетью, в которой находится.