Coin Lab

1 11700 1
Ethereum — Глава 6 (Контракты и транзакции).

 

 Контракты и транзакции

Введение

Ethereum — это платформа, целью которой является позволить людям легко записывать децентрализованные приложения (Đapps) , используя технологию блокчейна. Децентрализованное приложение – это приложение, которое предоставляет особые сервисы для своих пользователей, но которое имеет важную особенность – то, что само по себе приложение не зависит от существования какой-либо специальной стороны. Вместо того, чтобы действовать в качестве внешнего интерфейс-клиента для продажи или предоставления особых сервисов стороны, Đapp служит в качестве инструмента, объединяющего людей и организации, находящихся на противоположных сторонах интерактивного использования, и помогающего им взаимодействовать без какого-либо централизованного посредника.

Даже необходимые «промежуточные» функции, типичные для централизованных провайдеров домена, такие как фильтрация, управление идентификационной информацией, решение споров, либо управляются напрямую сетью, либо остаются открытыми для общего участия, используя инструменты, подобные системам внутренних символов internal token systems и систем репутаций reputation systems, чтобы обеспечить пользователей получить доступ к высококачественным сервисам. Ранние версии приложений Đapps включают BitTorrent для раздачи файлов и Bitcoin для валюты. Ethereum берет основные разработки, используемые BitTorrent и Bitcoin, равноранговую сеть и блокчейн, и объединяет их, чтобы позволить разработчикам использовать данные технологии в любых целях. Ethereum блокчейн можно по-другому описать как блокчейн с встроенным языком программирования, или как основанную на согласованности глобально исполняемую виртуальную машину. Часть протокола, которая фактически управляет внутренним состоянием и компьютеризацией, относится к Виртуальной машине Ethereum (Ethereum Virtual Machine (EVM)). С практической точки зрения, EVM можно представить в виде большого децентрализованного компьютера, содержащего миллионы объектов, называемых «аккаунтами», которые способны поддерживать внутреннюю базу данных, исполняемый код, и общаться друг с другом. Существует два типа аккаунтов:

1. Контролируемый извне аккаунт (EOAs): аккаунт, контролируемый закрытым ключом, и если вы владеете закрытым ключом, связанным с EOA , у вас имеется возможность отправлять из него эфиры (ether) и сообщения.

2. Контракт: аккаунт, имеющий собственный код, контролируется кодом.

По умолчанию, среда выполнения Ethereum является безжизненной; ничего не происходит, и состояние каждого аккаунта остается неизменным. Тем не менее, любой пользователь может запустить действие, отправив транзакцию из контролируемого извне аккаунта, настроив работу Ethereum. Если транзакция предназначена для другого аккаунта EOA, то транзакция может перевести несколько эфиров (ether) , иначе она ничего не делает. Однако, если назначением является контракт, то контракт, в свою очередь, активирует и автоматически управляет свой код. Код имеет способность чтения/записи в собственное внутреннее хранилище (базу данных, состоящую из 32-байтовых ключей для 32-байтовых значений), чтения хранилища полученных сообщений, и отправки сообщений другим контрактам, запуска их выполнения. Как только выполнение прекращается, и все под-выполнения, запущенные сообщением, отправленным остановкой контракта (все это происходит в детерминированном и синхронном порядке, т.е. под-вызов полностью завершается до того, как оригинальный вызов идет дальше parent call), среда выполнения снова останавливается.

Обычно контракты служат для четырех целей:

1. Поддерживают хранение данных, представляя нечто полезное либо для других контрактов, либо для внешнего мира; примером этого будет контракт, подражающий валюте, и другим примером будет контракт, записывающий членство в определенной организации.
2. Служит как аккаунт. Контролируемый извне, с более сложной политикой доступа; это называется «направляющим контрактом» и обычно включает в себя простую пересылку входящих сообщений с определенным предназначением, только при наличии определенных условий; например, можно иметь направляющий контракт, который ожидает, пока два из предоставленных трех закрытых ключей подтвердят определенное сообщение до его пересылки (т.е. мультиподпись multisig). Более сложные направляющие контракты имеют различные условия, основанные на характере отправляемых сообщений; простейший пример использования для данного функционала – это предел вывода, что преодолевается при помощи более сложной процедуры доступа.
3. Управляет непрерывным контрактом или отношениями между множеством пользователей. Примерами этого являются финансовый контракт, эскроу с определенным набором медиаторов, либо какой-то вид страховки. Можно также иметь открытый контракт, который одна сторона оставляет открытым для другой стороны, чтобы заниматься им в любое время; примером этого является контракт, который автоматически выплачивает премию всем, кто предлагает ценное решение какой-либо математической задачи, или доказывает, что он предоставляет какой-либо компьютерный ресурс.
4. Предоставляет функции другим контракта дополнительно служит в качестве библиотеки программного обеспечения.

Контракты взаимодействуют друг с другом посредством деятельности, которая по-другому называется «вызов» или «отправка сообщений». «Сообщени» — это объект, содержащий некоторое количество ether (особая внутренняя валюта, используемая в Ethereum с основной целью оплаты транзакций), байтовый массив данных любого размера, адреса отправителя и получателя. Когда контракт получает сообщение, у него имеется опция возврата некоторых данных, которые первоначальный отправитель сообщения может незамедлительно использовать. Таким образом отправка сообщения в точности аналогична вызову функции. Т.к. контракты могут выполнять такие разные роли, мы понимаем, что они могут взаимодействовать друг с другом. В качестве примера представьте ситуацию, когда Элис и Боб заключают пари на 100 GavCoin, что температура в Сан-Франциско ни при каком условии не превысит 35ºC в следующем году. Тем не менее, Элис очень бдительна, и ее главный аккаунт использует направляющий контракт, который отправляет сообщения только после получения подтверждения двух из трех закрытых ключей. Боб помешан на квантовой криптографии quantum cryptography, т.о. он использует направляющий контракт, который передает только сообщения, подписанные Lamport –подписями наряду с традиционными   ECDSA (но так как он консерватор, он предпочитает использовать версию подписи Lamport sigs, основанную на SHA256, которая не поддерживается напрямую в Ethereum). Самому по себе спорному контракту необходимо получить данные о погоде в Сан-Франциско от другого контракта, и ему также необходимо общаться с контрактом GavCoin c, когда ему нужно фактически отправить GavCoin либо Элис, либо Бобу (или, точнее, в направляющий контракт Элис или Боба). Мы можем продемонстрировать отношения между аккаунтами следующим образом:

contract_relationship

Когда Боб хочет завершить пари, происходят следующие этапы:

1. Транзакция отправляется, запуск сообщения из аккаунта EOA Боба в направляющий контракт Боба.
2. Направляющий контракт Боба отправляет хэш сообщения и подпись Lamport контракту, который функционирует в качестве библиотеки подтверждения подписи Lamport.
3. Библиотека подтверждения подписи Lamport видит, что Боб хочет основанную на SHA256 подпись Lamport sig, т.о. она много раз вызывает библиотеку SHA256, что необходимо для подтверждения подписи.
4. Как только библиотека подтверждения подписи Lamport возвращает 1, что означает, что подпись была подтверждена, она направляет сообщение контракту, представляющему пари.
5. Спорный контракт проверяет контракт, предоставляющий температуру в Сан-Франциско, чтобы узнать температуру.
6. Спорный контракт видит, что ответ на сообщения показывает, что температура составляет выше 35ºC, т.о. он отправляет сообщение контракту GavCoin переместить GavCoin из его аккаунт в направляющий контракт Боба.

Имейте в виду, что GavCoin «хранится» в качестве входов в базу данных GavCoin; слово «Аккаунт» в контексте этапа 6 просто означает, что данные воодятся в хранилище контракта GavCoin с ключом для адреса спорного контракта и значение его баланса. После получения данного сообщения, контракт GavCoin понижает данное значение какой-то суммой и увеличивает значение на входе в соответствии с адресом направляющего контракта Боба. Данные этапы можно рассмотреть в следующей диаграмме:

contract_relationship2


Типы аккаунтов и транзакций

В состоянии Ethereum существует два типа аккаунтов:

  • Нормальные, или контролируемые извне аккаунты, и
  • Контракты, т.е. фрагменты кода.

Оба типа аккаунтов имеют баланс эфиров (ether). Транзакции можно запускать из обоих типов аккаунтов, хотя контракты запускают транзакции только в качестве ответа на полученные транзакции. Следовательно, все действие блокчейна ethereum приводится в движение транзакциями, фиксированными их аккаунтов, контролируемых извне. Простейшими транзакциями являются транзакции передачи эфиров (ether) . Но перед рассмотрением этого, вам следует прочитать информацию об аккаунтах, и, возможно, о   майнинге.


 

Перевод Ether

Если на аккаунте, которым вы пользуетесь как отправитель, имеется достаточно финансов, нет ничегопроще перевода эфиров ether. Но именно поэтому вы должны быть осторожны! Вы предупреждены.

[box]eth.sendTransaction({from: ‘0x036a03fc47084741f83938296a1c8ef67f6e34fa’, to:’0xa8ade7feab1ece71446bed25fa0cf6745c19c3d5′, value: web3.toWei(1, «ether»)})[/box]

обратите внимание на конвертацию единицы в поле value. Стоимости транзакций выражаются в weis, наиболее гранулированных единицах стоимости. Если вы хотите использовать другую единицу (как, например ether в примере выше), воспользуйтесь функцией web3.toWei для конверсии.

Также помните о том, что сумма, списанная с исходного аккаунта, будет немного больше суммы, поступившей на принимающий аккаунт. Разницу составит небольшая плата за транзакцию, которую мы более детально обсудим позднее.

Контракты могут получать переводы таким же образом, как контролируемые акаунты, но они также могут принимать более сложные транзакции, которые фактически управляют (частично) их кодом и обновляют их состояние. Чтобы понять данные транзакции, требуется элементарное понимание контрактов.


 

Запись контракта

Контракты существуют в блокчейне в характерном для Ethereum бинарном формате. (Виртуальная машина Ethereum (=EVM) байт-код). Тем не менее, контракты обычно записываются на высокоуровневом языке программирования solidity, а затем компилируются в байт-код для загрузки в блокчейн. Имейте в виду, что также существуют другие языки, а именно serpent и LLL. Традиционный Mutan (ранний язык, напоминающий язык Си), больше не поддерживается.

Ресурсы языка

Solidity

Документы и инструкции:

Примеры:

Компиляторы

Serpent

Cреды разработок контракта/Dapp

  • Mix standalone IDE или
  • Встроенный браузер Cosmo, присоединяющий к geth через RPC.

 

Компилирование контракта

Контракты существуют в блокчейне в характерном для Ethereum бинарном формате. (Виртуальная машина Ethereum (=EVM) байт-код). Тем не менее, контракты обычно записываются на высокоуровневом языке программирования solidity, а затем компилируются в байт-код для загрузки в блокчейн. Для релиза frontier , geth поддерживает solidity-компиляцию через системный вызов  solc — solidity- компилятор командной строки (авторы Кристиан Р. И Лефтерис К.) Вы можете попробовать   Solidity- компилятор в реальном времени (Кристиан Р) или Cosmo или Mix. Если вы запустили свою geth ноду, вы можете проверить доступность solidity –компилятора. Произойдет следующее, если нет:

[box]eth.getCompilers()
[» ]
> eth.compile.solidity(«»)
error: eth_compileSolidity method not implemented
Invalid JSON RPC response[/box]

После того, как вы нашли способ установки solc, убедитесь, что он находится на пути path. Если eth.getCompilers() все еще не обнаружил его (возвращает пустой массив), вы можете настроить текущий путь на sol исполнимый модуль командной строки, при помощи флага solc .

[box]geth —datadir ~/frontier/00 —solc /usr/local/bin/solc —natspec[/box]

Вы также можете настроить опцию во время выполнения через консоль:

[box]> admin.setSolc(«/usr/local/bin/solc»)
solc v0.9.13
Solidity Compiler: /usr/local/bin/solc
Christian <[email protected]> and Lefteris <[email protected]> (c) 2014-2015
true [/box]

Давайте возьмем этот простой источник контракта:

[box]> source = «contract test { function multiply(uint a) returns(uint d) { return a * 7; } }» [/box]

This contract offers a unary method: called with a positive integer a, it returns a * 7. You are ready to compile solidity code in the geth JS console using eth.compile.solidity:

[box]> contract = eth.compile.solidity(source).test
{
code:
‘605280600c6000396000f3006000357c0100000000000000000000000000000000
00000000000000000000000090048063c6888fa
114602e57005b60376004356041565b8060005260206000f35b600060078202905060
4d565b91905056’,
info: {
language: ‘Solidity’,
languageVersion: ‘0’,
compilerVersion: ‘0.9.13’,
abiDefinition: [{
constant: false,
inputs: [{
name: ‘a’,
type: ‘uint256’
} ],
name: ‘multiply’,
outputs: [{
name: ‘d’,
type: ‘uint256’
} ],
type: ‘function’
} ],
userDoc: {
methods: {
}
},
developerDoc: {
methods: {
}
},
source: ‘contract test { function multiply(uint a) returns(uint d) { return a * 7; } }’
}
}[/box]

Компилятор также доступен через RPC и, следовательно, через web3.js для любого встроенного браузера Ðapp, присоединенного к geth через RPC.

Следующий пример показывает вам интерфейс geth через JSON-RPC для использования компилятора.

[box]./geth —datadir ~/eth/ —loglevel 6 —logtostderr=true —rpc —rpcport 8100 —rpccorsdomain ‘*’ —mine
console 2>> ~/eth/eth.log
curl -X POST —data ‘{«jsonrpc»:»2.0″,»method»:»eth_compileSolidity»,»params»:[«contract test { function
multiply(uint a) returns(uint d) { return a * 7; } }»],»id»:1}’ http://127.0.0.1:8100 [/box]

Выход компилятора для одного контракта объединен в объект, представляющий единичный контракт, и сериализован как json. Фактическое возвращаемое значение  eth.compile.solidity — это карта имени контракта – пары объектов контракта. Т.к. имя нашего контракта — test, eth.compile. solidity(source).test предоставит вам контрактный объект для тестового контракта, содержащего следующие поля:

  •  code: компилированный EVM -код
  •  info: остальные компилированные выходы metainfo
    • source: исходный код
    • language: язык контракта (Solidity, Serpent, LLL)
    • languageVersion: версия языка контракта
    • compilerVersion: версия компилятора
    • abiDefinition: Определение приложения бинарного интерфейса
    • userDoc: NatSpec документация пользователя
    • developerDoc: NatSpec документация разработчика

Немедленное структурирование выхода компилятора (входной code и info) отражает два очень разных пути развития. Компилированный EVM-код отправляется в блокчейн с транзакцией создания контракта, того как остальные (данные) в идеале будет существовать в децентрализованном облаке как общедоступные данные о данных , дополняющие код в блокчейне.


 

Создание и разблокировка контракта

Как только у вас есть и разблокированный аккаунт, и некоторые финансы, вы можете создать контракт в блокчейне путем отправки транзакции на пустой адрес при помощи evm-кода как данного. Просто, ведь так?

[box]primaryAddress = eth.accounts[0]
contractAddress = eth.sendTransaction({from: primaryAddress, data: evmCode})[/box]

Все бинарные данные сериализуются в шестнадцатиричный вид. Шестнадцатиричные ряды всегда имеют шестнадцатиричный префикс 0x. Имейте в виду, что данный этап требует от вас оплаты за выполнение. Ваш баланс на аккаунте (который вы положили как отправитель в поле from ) сократится в соответствии с правилами gas VM, как только ваша транзакция сделает его блоком. Более подробно об этом позднее. Через некоторое время ваша транзакция будет включена в блок, подтверждая, что состояние приведено в согласованность.

Ваш контракт сейчас существует в блокчейне. Асинхронный способ выполнения того же самого выглядит следующим образом:

[box]eth.sendTransaction({from: primaryAccount, data: evmCode}, function(err, address) {
if (!err)
console.log(address);
}); [/box]


 

Взаимодействие с контрактами

eth.contract может использоваться для определения класса контракта, что соответствует интерфейсу контракта, описанному в его  ABI описании.

[box]var Multiply7 = eth.contract(contract.info.abiDefinition);
var myMultiply7 = Multiply7.at(address);[/box]

В настоящее время все функциональные вызовы, перечисленные в abi , доступны в реализации контракта. Вы может просто вызвать данные методы в реализации контракта и чейне sendTransaction({from: address}) или call()tк нему. Отличие между этими двумя состоит в том, что call выполняет «сухое управление»локально , на вашем компьютере, тогда как sendTransaction фактически будет выполнять вашу транзакцию для включения в блокчейн, и результаты ее выполнения в конечном итоге станут частью глобальной согласованности global consensus.Другими словами, используйте  call, если вы хотите просто вернуть значение, и используйте sendTransaction , если вас волнуют только о «побочные эффекты» в состоянии контракта.

В примере выше нет побочных эффектов, следовательно  sendTransaction только сжигает gas и увеличивает энтропию пространства. Вся «полезная» функциональность джумонстрируется при помощи call:

[box]myMultiply7.multiply.call(6)
42[/box]

Теперь предположите, что этот контракт не ваш, и вам нужна документация или обзор исходного кода. Это представляется возможным, делая доступным информационный пакет контракта и регистрируя его в блокчейне. admin.contractInfo API обеспечивает удобные методы для извлечения данного пакета для любого контракта, который выбрал регистрацию. Чтобы посмотреть, как это работает, почитайте о Contract Metadata (данные о данных контракта) или почитайте информационный раздел контракта данного документа.

[box]// get the contract info for contract address to do manual verification
var info = admin.contractInfo.get(address) // lookup, fetch, decode
var source = info.source;
var abiDef = info.abiDefinition
// verify an existing contract in blockchain (NOT IMPLEMENTED)
admin.contractInfo.verify(address)[/box]


 

Gas и стоимости транзакций

Так как же вы платите за все это? За кулисами транзакция определяет gas-предел, и gas-цену, которые могут быть определены напрямую в объекте транзакции. Gas-предел присутствует, чтобы защитить вас от кода, содержащего ошибки, работающего до тех пор, пока не закончатся ваши финансы. Продукт gasPrice и gas представляет максимальное количество Wei, которое вы хотите заплатить за выполнение транзакции. То, что вы определяете как gasPrice используется майнерами для упорядочения транзакций для включения в блокчейн. Это цена в Wei одной gas-единицы, в которых оцениваются VM –операции. Расходование gas, вызванное работой вашего контракта, будет покупаться ether , имеющиеся на вашем аккаунте, по цене, которую вы установили в транзакции при помощи gasPrice. Если у вас действительно достаточно ether , чтобы покрыть все требования gas для завершения работы кода , обработка прерывается, и промежуточное состояние изменяет отмену транзакции на предварительный снепшот. Gas, используемый в месте остановки выполнения, все равно используется, поэтому ether-баланс вашего аккаунта сократится. Эти параметры можно настроить на поля объектов транзакций gas и gasPrice. Поле value используется так же, как и транзакции перевода ether между номральными аккаунтами. Другими словами, перевод средств доступен между двумя аккаунтами, либо нормальным (т.е., контролируемым извне), либо контрактом. Если ваш контракт функционирует без наличия средств, вы будете наблюдать ошибку недостатка средств. Имейте в виду, что все средства на аккаунте контракта будут невозвратимо потеряны, как только мы выпустим Homestead (см.правила игры). Для тестирования и игры с контрактами вы можете использовать тестовую сеть или установить закрытую ноду (или кластер) , потенциально изолированную от всех остальных нод. Если после этого вы будете майнить, вы можете убедиться, что ваша транзакция будет включена в следующий блок. Промежуточные транзакции можно наблюдать при помощи:

[box]eth.getBlock(«pending», true).transactions[/box]

Блоки можно возвращать по числу (высоте) или по их хэшу:

[box]genesis = eth.getBlock(0)
eth.getBlock(genesis.hash).hash == genesis.hash
true[/box]

Используйте eth.blockNumber , чтобы получить текущую высоту блокчейна, и «самый последний» магический параметр доступа к текущему заголовку (новейший блок).

[box]currentHeight = eth.blockNumber()
eth.getBlock(«latest»).hash == eth.getBlock(eth.blockNumber).hash
true [/box]


 

Информация о контракте

 

В предыдущих разделах мы объясняли, как создавать контракт в блокчейне. Сейчас мы имеем дело с оставшимся выходом компилятора, данными о данных контракта или информацией контракта. Идея состоит в том, что

  • информация контракта загружается в каком-то определенном месте при помощи  url , который является общедоступным
  • любой может узнать, что представляет собой  url , зная адрес контракта

Данные требования достигаются очень просто использованием 2-этапоного реестра блокчейна. Первый этап регистрирует код контракта (хэш) в контракт под названием HashReg. Второй этап регистрирует url при помощи постоянного хэша в контракт UrlHint . Эти контракты простого реестра будут частью предложения   frontier. Использую данную схему, необходимо знать адрес контракта, чтобы найти url , и считывать фактический пакет информации метаданных контракта . Почитайте далее, чтобы понять, почему это полезно.

Итак, если вы – добросовестный создатель контракта, этапы будут следующими:

1. Получите файл информации о контракте json.
2. Переместите файл информации о контракте json на любой адрес url по выбору
3. Зарегистрируйте codehash ->content hash -> url (хэш-код – хэш-контент – url)
4. Переместиет сам контракт в блокчейн

Приложение JS API очень упрощает данный процесс, предоставляя помощников. Вызовите admin.contractInfo.register для извлечения информации из контракта, запишите его сериализацию json в определенный файл, подсчитайте хэш-контент файла и , наконец, зарегистрируйте этот хэш-контент в хэш кода контракта. Как только вы переместите этот файл на какой-либо url, вы можете использовать admin.contractInfo.registerUrl также для регистрации url с вашим хэш-контентом в блокчейне. (Имейте в виду, что в случае фиксированного контента адресованная модель используется в качестве хранения документов, url-hint больше не нужен.

[box]source = «contract test { function multiply(uint a) returns(uint d) { return a * 7; } }»
// compile with solc
contract = eth.compile.solidity(source).test
// send off the contract to the blockchain
address = eth.sendTransaction({from: primaryAccount, data: contract.code})
// extracts info from contract, save the json serialisation in the given file,
// calculates the content hash and registers it with the code hash in HashReg
// it uses address to send the transaction.
// returns the content hash that we use to register a url
hash = admin.contractInfo.register(primaryAccount, address, contract,
«~/dapps/shared/contracts/test/info.json»)
// here you deploy ~/dapps/shared/contracts/test/info.json to a url
admin.contractInfo.registerUrl(primaryAccount, hash, url)[/box]


 

NatSpec

Данный раздел продолжает дальше рассказывать вам, что вы можете делать с контрактами и транзакциями, созданными в протоколе NatSpec. Solidity реализует эффективные комментарии smart comments стиля doxigen, которые могут использоваться впоследствии для генерирования различных интерфейсов мета-документов кода. Одним из таких способов применения будет генерирование пользовательских сообщений для подтверждения транзакции, на которое клиенты могут побудить пользователей..

Т.о., сейчас мы увеличиваем контракт multiply7 при помощи эффективного комментария smart comment , определяющего сообщение подтверждения пользователя (уведомление).

[box]contract test {
/// @notice Will multiply a by 7.
function multiply(uint a) returns(uint d) {
return a * 7;
}
}[/box]

Комментарий имеет выражения между исполнениями, которые подлежат оценке в то время, когда сообщение подтверждения транзакции передается пользователю. Переменные, которые относятся к параметрам вызовов методов, затем инстанцируются в соответствии с фактическими данными транзакции, отправленной пользователем (или dapp  пользователя). Поддержка NatSpec для уведомлений подтверждения полностью реализована в geth. NatSpec основывается как на определении abi, так и на компоненте userDoc, для генерации надлежащих подтверждений. Следовательно, чтобы получить доступ к этому, контракту необходимо зарегистрировать свой контракт вышеописанным способом.

Давайте рассмотрим полный пример. Как добросовестный умный разработчик контракта, вы сначала создаете свой контракт и перемещаете его в соответствии с рекомендованными выше этапами:

[box]source = «contract test {
/// @notice Will multiply a by 7.
function multiply(uint a) returns(uint d) {
return a * 7;
}

contract = eth.compile.solidity(source).test
contractaddress = eth.sendTransaction{from: primary, data: contract.code})
contenthash = admin.contractInfo.saveInfo(contract.info, «~/dapps/shared/contracts/test/info.json»)
admin.contractInfo.register(primary, contractaddress, contenthash)
// put it up on your favourite oldworld site:
admin.contractInfo.registerUrl(contentHash, «http://dapphub.com/test/info.json»)[/box]

Имейте в виду, что при использовании контент адресованной системы хранения, подобной swarm, второй этап не нужен, т.к. контент-хэш является уникальным адресом самого контента. В качестве безболезненного примера просто используйте схему файла url (не совсем облако, но покажет вам, как это работает) без необходимости перемещения. admin.contractInfo.registerUrl(contentHash,

[box]»file:///home/nirname/dapps/shared/contracts/test/info.json»).[/box]

Как только вы перестали быть разработчиком, swap находится там, где была, и притворяется, что вы – простой пользователь, отправляющий транзакцию неизвестному множественному 7 контракту. Вам необходимо запустить клиента при помощи флага —natspec , чтобы обеспечить эффективные подтверждения и считывание информации о контракте. Вы также можете настроить это в консоли при помощи  admin.contractInfo.start() andadmin.contractInfo.stop().

[box]geth —natspec —unlock primary console 2>> /tmp/eth.log[/box]

Сейчас в типе консоли:

[box]// obtain the abi definition for your contract
var info = admin.contractInfo.get(address)
var abiDef = info.abiDefinition
// instantiate a contract for transactions
var Multiply7 = eth.contract(abiDef);
var myMultiply7 = Multiply7.at(address);[/box]

And now try to send an actual transaction:

[box]> myMultiply7.multiply.sendTransaction(6)
NatSpec: Will multiply 6 by 7.
Confirm? [y/n] y
>[/box]

Когда данная транзакция включается в блок, где-нибудь на компьютере счастливчика-майнера, 6 умножается на 7, результат игнорируется. Миссия выполнена. Если транзакция не собрана, мы можем наблюдать это следующим образом:

[box]eth.pendingTransactions()[/box]

Это аккумулирует все отправленные транзакции, даже те, которые были отклонены и не включены в текущий майнинговый блок (транс-состояние). Это можно показать следующим образом:

[box]eth.getBlock(«pending», true).transactions()[/box]

если вы определите индекс своей отвергнутой транзакции, вы можете снова отправить ее с модифицированным gas-пределом и gas-ценой (оба опционных параметра):

[box]tx = eth.pendingTransactions()[1]
eth.resend(tx, newGasLimit, newGasPrice)[/box]


 

Руководство по контрактам

 Greeter (встречающий)

Теперь, когда вы владеете основами Ethereum, давайте перейдем к вашему первому серьезному контракту. Это большая открытая территория, и иногда вы можете почувствовать себя одиноко, поэтому первым пунктом в нашей повестке дня будет создание маленького автоматического компаньона, который будет приветствовать вас, как только вы почувствуете себя одиноко. Назовем его «Встречающий (Greeter)» .

[box]contract greeter {
function greet(bytes32 input) returns (bytes32) {
if (input == «») { return «Hello, World»; }
return input;
}
}[/box]

Как вы сможете увидеть, Greeter – это умный цифровой субъект, который живет в блокчейне и может разговаривать со всеми, кто взаимодействует с ним, основываясь на входе. Возможно, он не очень разговорчив, но он –отличный слушатель. Перед тем, как вы сможете загрузить его в сеть, вам понадобятся две вещи: компилированный код и Двоичный Интерфейс Приложений, своего рода руководство пользователя по взаимодействию с контрактом. Прежде всего необходимо научиться пользоваться компилятором. Вам необходимо иметь solidity-компилятор, встроенный в geth-консоль. Для тестирования используйте команду:

[box]eth.getCompilers()[/box]

Если компилятор установлен, вы увидите что-то вроде:

[box][‘Solidity’ ][/box]

Если вместо команды вы видите ошибку, прочитайте документацию по установке компилятора, используйте Aleth –ноль или используйте онлайн solidity компилятор. Если у вас установлен Geth Solidity –компилятор, его необходимо переформатировать, удалив используемую память, так чтобы он подходил в переменный ряд string variable:

[box]var greeterSource = ‘contract greeter { function greet(bytes32 input) returns(bytes32) { if (input == «»)
{ return «Hello, World!»; } return input; } }'[/box]

После того, как вы успешно выполнили описанное выше, компилируйте его и опубликуйте в сети при помощи следующих команд:

[box]var greeterCompiled = eth.compile.solidity(greeterSource).greeter
var primaryAccount = eth.accounts[0]
var greeterAddress = eth.sendTransaction({data: greeterCompiled.code, from: primaryAccount});[/box]

Вероятно, у вас запросят пароль, который вы ввели в начале. Вы выбираете, с какого аккаунта вы будете платить за транзакцию. Подождите, пока вашу транзакцию соберут, затем напечатайте:

[box]eth.getCode(greeterAddress)[/box]

Это должно вернуть код вашего контракта. Если возвращается “0x”, это значит, что ваша транзакция не подхвачена. Подождите еще немного. Если ничего не происходит, проверьте соединение с сетью.

[box]net.peerCount[/box]

Если у вас имеется более 0 pпиров, и на майнинг вашей транзакции требуется более минуты или двух, ваша gas-цена, должно быть, слишком низкая. Вы можете экспериментировать с различными gas –ценами следующим образом:

[box]var greeterAddress = eth.sendTransaction({data: greeterCompiled.code, from: primaryAccount, gas: 100000,
gasPrice: web3.toWei(10, «szabo»)});[/box]

Последняя gas-цена может быть проверена в Network Stats Dashboard (Информационная панель статистики сети). Не слишком зависайте на условиях особых единиц или значениях вышеуказанных чисел, просто модифицируйте цепь. Идите выше и вы сможете достичь gas-предела блока, идите ниже, и цена может опуститься, или вы сможете подобрать gas, недостаточный для транзакции.

После того, как ваш код принят, , eth.getCode(codeAddress) вернет ряд, представляющий собой ваш компилированный код в шестнадцатеричном изображении. Если все верно, поздравляем, ваш маленький Greeter — живой! Если контракт создается снова (выполняя другое eth.sendTransaction), он будет опубликован на новом адресе. Чтобы убедиться, что старые контракты можно очистить и восстановить их ether –баланс, не забудьте включить в него вызов Suicide . Теперь. Когда ваш контракт существует в сети, все могут взаимодействовать с ним, инстанцируя локальную копию. Но чтобы это сделать вашему компилятору необходимо знать, как с этим взаимодействовать, для чего и предназначен Двоичный Интерфейс Приложений (ABI). Вот как нужно инстанцировать контракт:

[box]greeterContract = eth.contract(greeterCompiled.info.abiDefinition)
greeterInstance = new greeterContract(greeterAddress)[/box]

Совет: если solidity-компилятор не установлен надлежащим образом в вашем компьютере, вы можете получить ABI из онлайн компилятора. Для этого используйте код , представленный ниже, осторожно заменяя первую строку переменной интерфейсом abi з вашего компилятора.

[box]greeterAbiDefinition = [{ constant: false, inputs: [{ name: ‘input’, type: ‘bytes32’ } ], name:
‘greet’, outputs: [{ name: », type: ‘bytes32’ } ], type: ‘function’} ]
greeterContract = eth.contract(greeterAbiDefinition)
greeterInstance = new greeterContract(greeterAddress)[/box]

ваш пример готов. Чтобы его вызвать, просто напечатайте следующую команду в своем терминале:

[box]greeterInstance.greet.call(«»);[/box]

Если ваш greeter ответил  “Hello World”  — поздравляем, вы только что создали своего первого цифрового бота-собеседника! Попробуйте еще раз при помощи:

[box]greeterInstance.greet.call(«hi»);[/box]

Попробуйте сами: Вы можете экспериментировать, меняя его параметры, делая его умнее. Вы можете заставить его собирать ether по его умному совету , добавив:

[box]if (msg.value>0) { return «Thanks!»; }[/box]

До первого ответного утверждения.


Регистратор

NameReg

Все аккаунты в сети ссылаются на свой общедоступный адрес. Но адреса — длинные, трудные для записи и запоминания, и их нельзя изменить. Последнее особенно важно, если вы хотите иметь возможность создавать новые акаунты в своем имени, или обновлять код вашего контракта. Для решения этого вопроса имеется контракт-регистратор, который используется для связи длинных адресов с короткими, понятными именами. Имена должны использовать только буквенно-цифровые символы и не могут содержать пробелы. В будущих релизах регистратор имени, скорее всего, будет применять аукцион, чтобы предотвратить захват имен, но пока он действует по принципу «первый пришел – первый получил». Т.о., если имя еще никем не зарегистрировано, вы можете его получить. Для начала выберите имя:

[box]var myName = «bob»[/box]

Затем проверьте доступность своего имени:

[box]registrar.addr(myName)[/box]

Если функция возвращает вам «0x00..», вы можете присвоить имя себе:

[box]registrar.reserve.sendTransaction(myName, {from: eth.accounts[0]});[/box]

Подождите, когда будет подобрана последняя транзакция. Ждите до тридцати секунд, затем попробуйте:

[box]registrar.owner(myName)[/box]

Если он возвращает вам в ответ ваш адрес, это означает, что вы владеете именем и способны установить выбранное вами имя на любой желаемый адрес:

[box]registrar.setAddress.sendTransaction(myName, eth.accounts[1], true,{from: eth.accounts[0]});[/box]

Вы можете отправить транзакцию всем , используя имя вместо аккаунта, просто

[box]eth.sendTransaction({from: eth.accounts[0], to: registrar.addr(«bob»), value: web3.toWei(1, «ether»)})[/box]

Совет: не перепутайте registrar.addr и registrar.owner. Первое относится к тому, на какой адрес направлено имя: любой может направить имя куда угодно, так же как любой может отправить ссылку в google.com, но только владелец имени может изменить и обновить ссылку. Вы можете настроить оба на один и тот же адрес.

Регистрация метаданных контракта

В дополнение к регистрации имени контракта, может быть полезным хранить определение ABI в общедоступном месте для обеспечения легкого доступа. Чтобы сделать это немного проще, предоставляются некоторые удобные способы регистрации и запоминания этих метаданных . Более подробно смотрите в  Взаимодействие с контрактами .

[box]// first, let’s start with a basic contract
// the name of the contract here is test and will appear in objects later
source = «contract test {\n» +
» /// @notice will multiply a by 7.\n» +
» function multiply(uint a) returns(uint d) {\n» +
» return a * 7;\n» +
» }\n» +
«} «;
// compile the Solidity contract and store the result
contract = eth.compile.solidity(source).test;
// set primary account variable
primary = eth.coinbase
// send a transaction and store the resulting address
contractaddress = eth.sendTransaction({from: primary, data: contract.code, gas: «1000000», gasPrice:
web3.toWei(«10», «szabo») });
// wait for the transaction to be mined
// define where to extract the metadata
filename = «/tmp/metadata.json»;
// register the contract and store the hash
hash = admin.contractInfo.saveInfo(contract.info, filename);
admin.contractInfo.register(primary, contractaddress, hash);
// wait for the transaction to be mined
// upload the metadata file. raw pastebin or github gist works great
url = «https://path/to/your/deployed/mycontract.json»;
admin.contractInfo.registerUrl(primary, hash, url);
// wait for the transaction to be mined[/box]

Однажды зарегистрированные метаданные могут быть с легкостью вызваны:

[box]info = admin.contractInfo.get(contractaddress);
console.log(info.abiDefinition);[/box]

Соединение вместе NameReg и MetadataReg делает довольно простым возможность делиться контрактами с другими:

[box]nameregName = «multiply7»; // contract namereg
info = admin.contractInfo.get(registrar.addr(nameregName));
var Multiply7 = eth.contract(info.abiDefinition);
var myMultiply7 = Multiply7.at(registrar.addr(nameregName));
myMultiply7.multiply.call(6);[/box]

или скомпонованные в одну строку:

[box]web3.eth.contract(eth.contract(admin.contractInfo.get(registrar.addr(«multiply7»)).abiDefinition)).
at(registrar.addr(nameregName)).multiply.sendTransaction(6, {from: primaryAddress}); [/box]


Coin-контракт

После того, как вы обезопасили свое имя, давайте создадим валюту для вашей страны. Валюты гораздо более интересны и полезны, чем кажутся, по сути своей, они представляю собой свободнообращающийся символ, но могут чем-то стать гораздо большим, в зависимости от того. Как вы будете их использовать. Их стоимость зависит от их использования: символ может использоваться для контроля доступа (входной билет), также их можно использовать для права голоса в организации (доля), в качестве «заполнителей»активов третьих сторон (сертификат собственности) или даже просто использоваться в качестве обмена стоимостью внутри контекста (валюты). Вы можете выполнять все это, создав централизованный сервер, но использование Ethereum символьного контракта предоставляет большую свободу: во-первых, это децентрализованный сервис и символы все еще можно обменивать, даже если оригинальный сервис по кокой-то пичине приходит в упадок. Код гарантирует, что ни один символ не будет создан, за исключением тех. Которые установлены в оригинальном коде. В итоге, когда каждый пользователь имеет собственный символ, это уничтожает сценарии, при которых одна единственная остановка сервера может привести к потере средств у тысячи клиентов.

Вот код контракта, который мы создаем:

[box]contract token {
mapping (address => uint) balances;
// Initializes contract with 10 000 tokens to the creator of the contract
function token() {
balances[msg.sender] = 10000;
}
// Very simple trade function
function sendToken(address receiver, uint amount) returns(bool sufficient) {
if (balances[msg.sender] < amount) return false;
balances[msg.sender] -= amount;
balances[receiver] += amount;
return true;
}
// Check balances of any account
function getBalance(address account) returns(uint balance){
return balances[account];
}
}[/box]

Если вы когда-либо занимались программированием, вам не покажется сложным понять происходящее: это контракт, которые генерирует 10 тысяч символов для создателя контракта, а затем позволяет всем, имеющим баланс, отправлять его остальным. Итак, давайте запустим его!

[box]var tokenSource = ‘contract token { mapping (address => uint) balances; function token() {
balances[msg.sender] = 10000; } function sendToken(address receiver, uint amount) returns(bool sufficient)
{ if (balances[msg.sender] < amount) return false; balances[msg.sender] -= amount;
balances[receiver] += amount; return true; } function getBalance(address account) returns(uint
balance){ return balances[account]; } }'[/box]

А теперь давайте настроим контракт, в точности, как мы это делали в предыдущем разделе. Т.к. это более сложный контракт, чем Greeter, мы добавим больше gas , чем требуется по умолчанию. Лишние Gas возвращаются.

[box]var tokenCompiled = eth.compile.solidity(tokenSource).token
var primaryAccount = eth.accounts[0]
var tokenAddress = eth.sendTransaction({data: tokenCompiled.code, from: primaryAccount, gas:1000000});[/box]

Подождите минуту и используйте код ниже, чтобы проверить, был ли перемещен ваш код.

[box]eth.getCode(tokenAddress)[/box]

Затем

[box]tokenContract = eth.contract(tokenCompiled.info.abiDefinition)
tokenInstance = new tokenContract(tokenAddress)[/box]

Вы может проверить свой баланс при помощи:

[box]tokenInstance.getBalance.call(primaryAccount)[/box]

Он должен содержать все 10 000 монет, созданных при опубликовании контракта. Т.к. нет другого установленного способа для выпуска новых монет, это все, которые существуют.
Сейчас, конечно, данные символы не очень-то полезны, если вы все их храните, поэтому, чтобы отправить их кому-либо еще, используйте команду:

[box]tokenInstance.sendToken.sendTransaction(eth.accounts[1], 100, {from: primaryAccount})[/box]

Причина того, что первая команда была.call() , а вторая команда была.sendTransaction()  — это то, что первая — это просто читаемая операция, а последняя использует gas для изменения состояния блокчейна, и в таком случае ей необходимо установить отправителя. Сейчас подождите минуту и проверьте балансы обоих аккаунтов:

[box]tokenInstance.getBalance.call(eth.accounts([0])
tokenInstance.getBalance.call(eth.accounts([1])[/box]

Попробуйте самостоятельно: Вы только что создали собственную криптовалюту, представьте все возможности! Прямо сейчас эта криптовалюта довольно ограниченна, т.к. имеется только 10,000 монет, и все они контролируются создателем монет, но вы можете это изменить. Добавив следующую функцию, вы выпустите монету для любого, кто обнаружит блок ethereum:

[box]mapping (uint => address) miningReward;
function claimMiningReward() {
if (msg.sender == block.coinbase && miningReward[block.number] == 0) {
balances[msg.sender] += 1;
miningReward[block.number] = msg.sender;
}
}[/box]

Это можно модифицировать во что-то еще: может быть, наградить кого-то, кто найдет решение для новой задачи, выиграет партию в шахматы, установит солнечную панель – насколько это можно перевести в контракт. Или может быть вы захотите создать центральный банк для вашей личной страны, чтобы отслеживать отработанные часы, задолженные услуги, или контролировать собственность. В этом случае вы могли бы захотеть добавить функцию, позволяющую банку удаленно замораживать фонды и разрушать символы при необходимости. Будущие усовершенствования, еще не воплощенные:

  • Формальная защита – это способ, при котором разработчик контракта утверждает некоторые неизменные качества контракта, например общая капитализация монеты.
  • Стандарт мета-монеты – это предложенная стандартизация функциональных имен для монеты и символьных контрактов, чтобы позволить им автоматически добавляться к другому контракту ethereum , который использует трейдинг в качестве обмена или эскроу.

 

Crowdfunder (сборщик средств)

На создание страны требуется много средств и совместных усилий. Вы можете запросить субсидирование, но инвесторы предпочитают вкладывать в проекты, на счет которых они более уверены, что последние получать поддержку и надлежащее финансирование. Вот пример, когда прямое финансирование проекта было бы идеальным: вы ставите цель и срок для ее достижения. Если вы не достигли своей цели, все предоставленные средства возвращаются, т.о. сокращая риск для вкладчиков. Т.к. код является открытым и проверяемым, нет необходимости в централизованной платформе, и , следовательно, единственные платы, которые нужно вносить, это платы gas. Т.к. у вас уже имеется собственная внутренняя валюта, вы можете ее использовать для сбора средств.  В данном контракте каждый, кто вкладывает средства, также получает пропорциональное количество символов, созданных вами. Это можно использовать , как доказательство гражданства, как совместную систему или просто как награду за их помощь в качестве первых участников. Внимание: Все контракты будут уничтожены в конце Frontier. Если балансы на нормальных адресах переместятся в Homestead, , то балансы в контрактах, а также адреса, имеющие менее 1 ether, не будут переведены. Поэтому используйте контракт сбора средств в тестовых целях и не размещайте на нем внушительных сумм без определенных на то целей.

[box]contract token{
function sendToken(address receiver,uint256 amount)returns(bool sufficient){}
function getBalance(address account)returns(uint256 balance){}
}
contract crowdSale {
address admin;
address beneficiary;
uint fundingGoal;
uint numFunders;
uint amount;
uint deadline;
uint price;
token tokenReward;
mapping (uint => Funder) funders;
// data structure to hold information about campaign contributors
struct Funder {
address addr;
uint amount;
}
// at initialization, setup the owner
function CrowdSale() {
admin = msg.sender;
}
function setup(address _beneficiary, uint _fundingGoal, uint _deadline, uint _price, address _reward)
returns (bytes32 response){
if (msg.sender == admin && !(beneficiary > 0 && fundingGoal > 0 && deadline > 0)) {
beneficiary = _beneficiary;
fundingGoal = _fundingGoal;
deadline = _deadline;
price = _price;
tokenReward = token(_reward);
return «campaign is set»;
} else if (msg.sender != admin) {
return «not authorized»;
} else {
return «campaign cannot be changed»;
}
}
//function to contributes to the campaign
function contribute() returns (bytes32 response) {
Funder f = funders[numFunders++];
f.addr = msg.sender;
f.amount = msg.value;
amount += f.amount;
tokenReward.sendToken(msg.sender, f.amount/price);
return «thanks for your contribution»;
}
// checks if the goal or time limit has been reached and ends the campaign
function checkGoalReached() returns (bytes32 response) {
if (amount >= fundingGoal){
uint i = 0;
beneficiary.send(amount);
suicide(beneficiary);
return «Goal Reached!»;
}
else if (deadline <= block.number){
uint j = 0;
uint n = numFunders;
while (j <= n){
funders[j].addr.send(funders[j].amount);
funders[j].addr = 0;
funders[j].amount = 0;
j++;
}
suicide(beneficiary);
return «Deadline passed»;
}
return «Not reached yet»;
}
}
Compile it and copy the following commands on the terminal:
> var crowdsaleCode =
«0x5b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b6107c
08061003b6000396000f3006000357c010000000000000000000000000000000000000000000
0000000000000900480635b2329d414610045578063670c884e1461005a578063d7bb99ba1461007
b57005b610050600435610409565b8060005260206000f35b6100716004356024356044356064356
084356101f6565b8060005260206000f35b61008361008d565b8060005260206000f35b600060006
00060086000506000600360008181505480929190600101919050558152602001908152602001600
0206000915091503382825060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908
30217905550348282506001016000508190555081815060010160005054600460008282825054019
2505081905550600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffff
ffffffffffffffffffff1663412664ae60206000827c010000000000000000000000000000000000000000
00000000000000000260005260043373ffffffffffffffffffffffffffffffffffffffff1681526020016006600
050548787506001016000505404815260200160006000866161da5a03f16101c357005b5050600051
507f7468616e6b7320666f7220796f757220636f6e747269627574696f6e0000000092506101f1565b50
5090565b6000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673fffffffffffffffffffff
fffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480156102b0575060006001600090549061010
00a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1611801561029d57506000
600260005054115b80156102ae57506000600560005054115b155b610363576000600090549061010
00a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373fffffffffffffffffffffffffff
fffffffffffff161415610336577f63616d706169676e2063616e6e6f74206265206368616e67656400000000
000090506104005661035e565b7f6e6f7420617574686f72697a65640000000000000000000000000
000000000009050610400565b6103ff565b85600160006101000a81548173fffffffffffffffffffffffffffffffffff
fffff02191690830217905550846002600050819055508360056000508190555082600660005081905
55081600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055507f63616d70
6169676e2069732073657400000000000000000000000000000000009050610400565b5b959450
50505050565b6000600060006000600260005054600460005054101561057a57436005600050541
11561043557610575565b6000915060036000505490505b808211151561054d576008600050600083
815260200190815260200160002060005060000160009054906101000a900473ffffffffffffffffffffffffff
ffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166000600860005060008581526020019081526020016
00020600050600101600050546000600060006000848787f16104d257005b505050600060086000
50600084815260200190815260200160002060005060000160006101000a81548173ffffffffffffffffffffff
ffffffffffffffffff0219169083021790555060006008600050600084815260200190815260200160002060
0050600101600050819055508180600101925050610442565b7f446561646c696e65207061737365640
00000000000000000000000000000000093506107b8565b610790565b600092506001600090549
06101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166000600460005
0546000600060006000848787f16105d157005b505050600760009054906101000a900473ffffffffffff
ffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663412664ae60206000827c0100000000000
0000000000000000000000000000000000000000000000260005260046001600090549061010
00a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016007600090
54906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f8b2cb4f60
206000827c010000000000000000000000000000000000000000000000000000000002600052
60043073ffffffffffffffffffffffffffffffffffffffff16815260200160006000866161da5a03f161070d57005b50506
00051815260200160006000866161da5a03f161072857005b505060005150600160009054906101000
a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff7f476f616c2052656163686
564210000000000000000000000000000000000000093506107b8565b7f4e6f74207265616368656
420796574000000000000000000000000000000000093506107b8565b50505091905056»
> var crowdsaleABI = [ { «constant» : false, «inputs» : [ { «name» : «campaignID», «type» : «uint256» } ],
«name» : «checkGoalReached», «outputs» : [ { «name» : «response», «type» : «bytes32» } ], «type» :
«function» }, { «constant» : false, «inputs» : [ { «name» : «_beneficiary», «type» : «address» }, { «name»
: «_fundingGoal», «type» : «uint256» }, { «name» : «_deadline», «type» : «uint256» }, { «name» : «_price»,
«type» : «uint256» }, { «name» : «_reward», «type» : «address» } ], «name» : «setup», «outputs» : [ {
«name» : «response», «type» : «bytes32» } ], «type» : «function» }, { «constant» : false, «inputs» : [],
«name» : «contribute», «outputs» : [ { «name» : «response», «type» : «bytes32» } ], «type» : «function» }] [/box]

Отправьте свой аккаунт-отправитель и сохраните получившийся в результате адрес контракта:

[box]var primaryAccount = eth.accounts[0]
var crowdsaleAddress = web3.eth.sendTransaction({data: crowdsaleCode, from: primaryAccount, gas:1000000}); [/box]

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

[box]eth.getCode(crowdsaleAddress)[/box]

Если он перемещен, выполните следующие команды для его локальной инстанциации.

[box]CrowdsaleContract = web3.eth.contract(crowdsaleABI)
crowdsaleInstance = CrowdsaleContract.at(crowdsaleAddress)[/box]

Первым вашим шагом будет настроить контракт. Это можно сделать только один раз, и необходимо, чтобы он пришел из того же аккаунта, который первоначально создал контракт.

[box]var beneficiary = eth.accounts[1]; // create an account for this
var fundingGoal = web3.toWei(100, «ether»); // raises a 100 ether
var deadline = eth.blockNumber + 200000; // about four weeks
var price = web3.toWei(2, «ether»); // the price of the tokens, in ether
var reward = tokenAddress; // the token contract address. [/box]

В Получателе вставьте новый адрес, который будет получать привлеченные средства. Цель финансирования – это сумма привлеченных ether. Срок измеряется в блоктаймах (интервалах блока), равных в среднем 12 секундам, т.о. по умолчанию он равен примерно 4 неделям. Цена сложная: но попробуйте просто изменить число 2 на количество символов, которые участники получат за каждый вложенный ether. В конечном итоге наградой должен стать контракт адреса символов, который вы создали в последнем разделе.

[box]crowdsaleInstance.setup.sendTransaction(beneficiary, fundingGoal, deadline, price, reward, {from: primaryAccount}); [/box]

Не забудьте найти свой вновь созданный контракт с необходимыми символами, чтобы он мог платить участникам!

[box]tokenInstance.sendToken.sendTransaction(crowdsaleAddress, 200,{from: primaryAddress})[/box]

Сейчас вы настроили и каждый может настроить следуя вышеуказанным шагам. Во-первых отправьте им адрес который вы только что создали:

[box]var crowdsaleAddress = «0x000000»
var crowdsaleABI = [ { «constant» : false, «inputs» : [ { «name» :
«campaignID», «type» : «uint256» } ], «name» : «checkGoalReached»,
«outputs» : [ { «name» : «response», «type» : «bytes32» } ],
«type» : «function» }, { «constant» : false, «inputs» : [ { «name» :
«_beneficiary», «type» : «address» }, { «name» : «_fundingGoal»,
«type» : «uint256» }, { «name» : «_deadline», «type» : «uint256»
} ], «name» : «init», «outputs» : [ { «name» : «response»,
«type» : «bytes32» } ], «type» : «function» }, { «constant» : false,
«inputs» : [], «name» : «contribute», «outputs» : [ { «name» : «response»,
«type» : «bytes32» } ], «type» : «function» }]
crowdsaleContract = web3.eth.contract(crowdsaleABI)
crowdsaleInstance = new crowdsaleContract(crowdsaleAddress)
var amount = web3.toWei(1, «ether»)
crowdsaleInstance.contribute.sendTransaction({from: primaryAddress, value: amount })

Сейчас подождите минуту чтобы войти в блок и можете проверить если вы получили token либо проверьте баланс контракта, выполнив следующее:

[box]eth.getBalance(crowdsaleAddress);[/box]

Ethereum не управляет контрактами самостоятельно, их необходимо запрашивать, т.о., как только проходит срок, все могут отправлять средства либо получателю, либо обратно финансистам (при неудаче), при помощи:

[box]crowdsaleInstance.checkGoalReached.sendTransaction({from: primaryAddress })[/box]


 

Демократический DAO

Децентрализованная анонимная организация : Демократический Контракт Итак, вы привлекли деньги для своей новой страны, но пока это Олигархия, где все деньги контролируются небольшой группой людей, имеющих ключ к вашему кошельку с мультиподписью. Это не похоже на грандиозное начало нового общества, не так ли? Так давайте создадим демократическую организацию.

[box]contract multisig {
function multisig() {
// when a contract has a function with the same name as itself,
// then that function is run at startup
m_numOwners = 1;
m_required = m_numOwners;
m_owners[msg.sender] = m_numOwners;
}
function transact(address _to, uint _value) external onlyowner {
// Each transaction is converted in a hash and awaits confirmation
if (confirm(m_owners[msg.sender], sha3(_to, _value)))
_to.send(_value);
}
function addOwner(address _newOwner) external onlyowner {
// Any owner can invite more, and all transactions need to be approved by more than half of them
if (!(isOwner(_newOwner))) {
m_numOwners++;
m_required = m_numOwners / 2 + 1;
m_owners[_newOwner] = m_numOwners;
}
}
function confirm(uint _owner, bytes32 _hash) internal returns (bool) {
// Does some bitshifting magic to confirm transactions
uint ownerBit = 2**_owner;
if (m_pending[_hash].confirmed & ownerBit == 0) {
m_pending[_hash].confirmed &= ownerBit;
if (++m_pending[_hash].numConfirmations >= m_required) {
delete m_pending[_hash];
return true;
}
}
}
// What follows are variables that are used to describe the function
modifier onlyowner() { if (isOwner(msg.sender)) _ }
// Accessors to allow reading function variables
function isOwner(address addr) returns (bool) { return m_owners[addr] > 0; }
function totalOwners() returns (uint) { return m_numOwners; }
function totalRequiredConfirmations() returns (uint) { return m_required; }
function pendingConfirmations(address _to, uint _value) returns (uint) { return m_pending[sha3(_to,
_value)].numConfirmations; }
// Объявление структуры контракта
uint m_numOwners;
uint m_required;
mapping(address => uint) m_owners;
mapping(bytes32 => Pending) m_pending;
struct Pending {
uint confirmed;
uint numConfirmations;
}
}[/box]

В этом контракте прямо сейчас происходит много вещей, но если у вас есть опыт использования программных языков, вам, скорее всего, удастся вчитаться в него. Основное –то, что это коллективный аккаунт со множеством владельцев аккаунта. Любой владелец может пригласить других людей стать владельцами, и любой владелец может запросить, чтобы деньги были отправлены на какой-либо другой аккаунт. Но чтобы транзакция была принята, необходимо согласия по крайней мере 50%+1 держателей аккаунта. Сейчас можно брать этот контракт и компилировать его через предоставленный онлайн инструмент. Самым важным является компилированный шестнадцатеричный код и интерфейс контракта. Замените код ниже на то, что предоставит вам компилятор.

[box]var compiledCode =
«0x5b6001600060005081905550600060005054600160005081905550600060005054600260005
060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819055505b6
103db806100636000396000f3006000357c01000000000000000000000000000000000000000
0000000000000000090048063243669ad146100665780632f54bf6e14610078578063510f43f61461
008d5780637065cb481461009f578063a7cf6e22146100b0578063f77ac668146100c857005b61006e6
1026d565b8060005260206000f35b61008360043561022c565b8060005260206000f35b610095610
27f565b8060005260206000f35b6100aa60043561019f565b60006000f35b6100be60043560243561
0291565b8060005260206000f35b6100d66004356024356100dc565b60006000f35b6100e5336102
2c565b6100ee5761019a565b610160600260005060003373ffffffffffffffffffffffffffffffffffffffff1681526020
019081526020016000206000505460408473ffffffffffffffffffffffffffffffffffffffff166c010000000000000
00000000000028152601401838152602001604090036040206102f9565b61016957610199565b817
3ffffffffffffffffffffffffffffffffffffffff166000826000600060006000848787f161019557005b5050505b5b5
b5050565b6101a83361022c565b6101b157610228565b6101ba8161022c565b156101c457610227565b
600060008181505480929190600101919050555060016002600060005054040160016000508190
5550600060005054600260005060008373ffffffffffffffffffffffffffffffffffffffff168152602001908152602
001600020600050819055505b5b5b50565b60006000600260005060008473ffffffffffffffffffffffffffff
ffffffffffff16815260200190815260200160002060005054119050610268565b919050565b60006000
60005054905061027c565b90565b6000600160005054905061028e565b90565b60006003600050
600060408573ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140
184815260200160409003604020815260200190815260200160002060005060010160005054905
06102f3565b92915050565b600060008360020a905060008160036000506000868152602001908
152602001600020600050600001600050541614610331576103d3565b806003600050600085815
260200190815260200160002060005060000160008282825054169250508190555060016000505
460036000506000858152602001908152602001600020600050600101600081815054600101919
0508190551015610399576103d2565b600360005060008481526020019081526020016000206000
600082016000506000905560018201600050600090555050600191506103d4565b5b5b50929150
5056»
var multisigAbi = [ { "constant" : false, "inputs" : [], "name" : "totalOwners",
"outputs" : [ { "name" : "", "type" : "uint256" } ],
"type" : "function" }, { "constant" : false, "inputs" : [ { "name" :
"addr", "type" : "address" } ], "name" : "isOwner", "outputs" : [
{ "name" : "", "type" : "bool" } ], "type" : "function" }, {
"constant" : false, "inputs" : [], "name" : "totalRequiredConfirmations", "outputs" : [
{ "name" : "", "type" : "uint256" } ], "type" : "function" },
{ "constant" : false, "inputs" : [ { "name" : "_newOwner", "type
: "address" } ], "name" : "addOwner", "outputs" : [], "type" : "function" },
{ "constant" : false, "inputs" : [ { "name" : "_to", "type" :
"address" }, { "name" : "_value", "type" : "uint256" }
], "name" : "pendingConfirmations", "outputs" : [ { "name" : "",
"type" : "uint256" } ], "type" : "function" }, { "constant" : false,
"inputs" : [ { "name" : "_to", "type" : "address" }, {
"name" : "_value", "type" : "uint256" } ], "name" : "transact",
"outputs" : [], "type" : "function" }]
var sender = eth.accounts[0]
var codeAddress = eth.sendTransaction({data: compiledCode, from: sender}); [/box]

Подождите минуту, и выполните код ниже чтобы проверить, что ваш код был развернут .

[box]eth.getCode(codeAddress)[/box]

Если да, то выполните следующие команды для локального развертывания:

[box]MultisigContract = eth.contract(multisigAbi)
multisigInstance = MultisigContract.at(codeAddress)[/box]

The code is ready for use. The first thing you need to do is to add a new owner to it. If you want to test it with a friend, put his address here, but if you want to test it locally, you’ll need multiple accounts. Read the section “creating a new account” above, if you haven’t done so already.

[box]//.call().totalOwners()
//.call().totalRequiredConfirmations()
//.pendingConfirmations(eth.accounts[4], web3.toWei(1, "ether"))
var newSigner = eth.accounts[1]
multisigInstance.addOwner.sendTransaction(newSigner, {from: sender}) [/box]

Следующий этап - финансирование вашего коллективного аккаунта. Все контакты могут держать ether, совсем как нормальный аккаунт. Помните, что любой ether, отправленный в контракт, принадлежит контракту, и может быть перемещен только при особых обстоятельствах, настроенных кодом. Т.о., перед отправкой крупной суммы проверьте контракт с небольшой суммой средств, т.к. если что-то пойдет не так, деньги будут потеряны навсегда.

[box]var amount = web3.toWei(0.01, "ether");
eth.sendTransaction({from: sender, to: codeAddress, value: amount}) [/box]

Подождите минуту, когда сеть заберет транзакцию, затем вы можете вополнить данную команду для проверки баланса:

[box]eth.getBalance(codeAddress)[/box]

Если баланс не нулевой, значит, вы успешно профинансировали свой аккаунт, и это означает, что ваша предыдущая транзакция, добавляющая нового владельца в ваш аккаунт со множеством владельцев, также принята. Сейчас мы собираемся попросить, чтобы ваш аккаунт отправил деньги кому-то еще. Создайте третий аккаунт, чтобы быть получателем, и напечатайте следующий код:

[box]var beneficiary = eth.accounts[2]
multisigInstance.transact.sendTransaction(beneficiary, 1000, {from: sender}) [/box]

Если вы проверите баланс получателя или контракта, вы увидите, что они не изменились, и на этот раз это не вопрос минутного ожидания. Это произошло потому, что чтобы именно эта транзакция контракта была принята, необходимо одобрение по крайней мере половины плюс один владельцев аккаунта. Т.к. ваш контракт принадлежит только 2 аккаунтам, ему необходимо 2 одобрения. В этом случае это делается, когда второй аккаунт отправляет идентичную транзакцию – этот же получатель и точная сумма - как и предыдущую:

[box]multisigInstance.transact.sendTransaction(beneficiary, 1000, {from: newSigner})[/box]

Примечаниe: эта транзакция, т.к. она предназначена для изменения состояния блокчейна, требует выполнения gas. Если вы просто создадите аккаунт newSigner, и он не будет содержать финансы, он не сможет заплатить gas за выполнение. Просмотрите раздел, посвященный отправке транзакций, чтобы научиться отправлять деньги на аккаунт до его взаимодействия с блокчейном.

Подождите минуту и проверьте баланс обоих аккаунтов и получателя, и вы увидите, что баланс изменился.

[box]`js
eth.getBalance(beneficiary)
eth.getBalance(codeAddress)[/box]

Если получатель имеет какие -либо ненулевые средства, значит, вы только что создали контракт со множеством владельцев. Подумайте немного о возможностях: вы можете сгенерировать вторую подпись в другом устройстве, принадлежащем вам, и пользоваться этим в качестве второго устройства аутентификации, так что, если один из ваших главных ключей окажется скомпрометирован, ваши деньги все равно будут в безопасности. Или вы можете предоставить своим друзья или семье пользоваться второй подписью и использовать этот контракт как совместный аккаунт, или трастовый фонд. Это может вырасти до маленькой компании, где CFO должен будет согласовывать любые платежи, которые осуществляются с аккаунта компании.

Вы только что создали Децентрализованную Автономную Организацию. Это организм, состоящий из роботов и людей, живущих в блокчейне. Совсем как бот “Greeter”, которого вы создали ранее, как только что-то становится публичным, оно начинает существовать в блокчейне, следуя четким правилам. Если таковые были четко установлены в конституции, то никто не сможет растратить средства или остановить блокчейн, поэтому до выпуска в сеть необходимо потренироваться. Попробуйте самостоятельно: в настоящее время любой владелец может пригласить неограниченное количество других владельцев. Хотя существует техническое ограничение, т.к. после 256 владельцев контракт начнет странно себя вести, это также и вопрос доверия. Вы можете доверять кому-то и предоставить вторую подпись, но не пригласить неограниченно в другие аккаунты. Один пользователь- злоумышленник может присвоить весь акаунт, создав сотню закрытых аккаунтов и являясь единственным контролирующим все деньги. Вы можете решить такую проблему? Может быть, установить максимальное число владельцев, или ограничить людей, способных пригласить больше. . Также посмотрите. Сможете ли вы изменить контракт, чтобы создать требование минимального кворума, чтобы предложение прошло. Если вы можете, то попытайтесь установить правило, что если транзакция превышает определенное значение, ей потребуется сверхбольшинство, это не просто. Вы можете придумать способ избавиться от офиса иммиграции и предложить запрещенным участникам использовалть выборы?


вернуться к оглавлению

 

Теги

Блокчейн глазами IBM: зачем нужен проект HyperLedger и когда мир перейдёт на новую технологию В четверг, 10 ноября, IT-гигант IBM представит своё видение того,…
admin by admin
0 8286 0
Взгляд Microsoft на блокчейн-технологию: от слов к коду Представляем одного из ключевых спикеров Blockchain & Bitcoin Conference Russia…
admin by admin
0 4722 0
Блокчейн в банковской системе: взгляд Сбербанка Сбербанк России – один из лидеров банковского рынка по внедрению…
admin by admin
0 5726 0

Один коментарий к “Ethereum — Глава 6 (Контракты и транзакции).”

  1. admin
    admin     13.06.2015

    Есть неточности в переводе, просьба сообщайте если найдете

Leave a Reply

Войти
Регистрация
Отправить сообщение