


Schlüsselpunkte
- Story Dao verwendet den eigenen Vertrag von Openzeppelin, um sicherzustellen, dass nur der Eigentümer Verwaltungsfunktionen ausführen kann und so die Sicherheit und Kontrolle über DApp -Operationen verbessert.
- Story DAO -Verträge haben einstellbare Gebühren- und Dauerparameter und sind mit Sicherheitsmaßnahmen ausgestattet, um nicht autorisierte Änderungen zu verhindern, um sicherzustellen, dass nur der Eigentümer kritische Einstellungen ändern kann.
- Whitelist Management in Story DAO wird durch bezahlte Funktionen implementiert, die einen automatischen und bedingten Zugriff basierend auf dem Beitrag des Absenders ermöglichen.
- integrierte Teststrategien, einschließlich Solidität und JavaScript -Tests, sind entscheidend für die Überprüfung der Funktionalität und Sicherheit von Story DAO, wodurch der robuste Betrieb vor der Bereitstellung sichergestellt wird.
- Der Bereitstellungsprozess von Story DAO wird durch TRUFFL mit spezifischen Migrationsskripten und -konfigurationen vereinfacht, was einen reibungslosen Übergang von der Entwicklungsumgebung in die Produktionsumgebung ermöglicht.
Der dritte Teil dieser Tutorial -Serie beschreibt das Erstellen eines Dapps mit Ethereum, in der wir das Token für das Ethereum -Testnetzwerk Rinkeby erstellen und bereitstellen. In diesem Abschnitt werden wir damit beginnen, den DAO -Code von Story zu schreiben.
Wir werden uns anhand der im Einführungsartikel aufgeführten Kriterien führen.
Vertragsübersicht
Lassen Sie uns einen neuen Vertrags -StoryDao.sol erstellen, dessen Rahmen wie folgt lautet:
pragma solidity ^0.4.24; import "../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol"; import "../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol"; contract StoryDao is Ownable { using SafeMath for uint256; mapping(address => bool) whitelist; uint256 public whitelistedNumber = 0; mapping(address => bool) blacklist; event Whitelisted(address addr, bool status); event Blacklisted(address addr, bool status); uint256 public daofee = 100; // 百分之几,即 100 为 1% uint256 public whitelistfee = 10000000000000000; // 以 Wei 为单位,这是 0.01 以太币 event SubmissionCommissionChanged(uint256 newFee); event WhitelistFeeChanged(uint256 newFee); uint256 public durationDays = 21; // 故事章节持续时间(天) uint256 public durationSubmissions = 1000; // 故事章节持续时间(条目) function changedaofee(uint256 _fee) onlyOwner external { require(_fee <= 1000); // 限制最大费用为 10% daofee = _fee; emit SubmissionCommissionChanged(_fee); } function changewhitelistfee(uint256 _fee) onlyOwner external { require(_fee > 0); // 确保费用大于 0 whitelistfee = _fee; emit WhitelistFeeChanged(_fee); } function changeDurationDays(uint256 _days) onlyOwner external { require(_days >= 1); durationDays = _days; } function changeDurationSubmissions(uint256 _subs) onlyOwner external { require(_subs > 99); durationSubmissions = _subs; } }
Wir importieren Safemath, um wiederere Berechnungen durchzuführen, aber diesmal verwenden wir auch Zeppelins eigene Vertrag, mit dem jemand die Geschichte „besitzt“ und bestimmte Funktionen nur für Administratoren ausführen kann. Einfach ausgedrückt, es reicht aus, dass unser StoryDao besitzt wird.
Wir verwenden auch den einzigen Besitzermodifikator in diesem Vertrag. Funktionsmodifikatoren sind im Grunde genommen Erweiterungen und Plug-Ins für Funktionen. Der einzige Besitzermodifikator sieht folgendermaßen aus:
modifier onlyOwner() { require(msg.sender == owner); _; }
Wenn nur der Funktionen der Funktion hinzugefügt wird, wird der Körper der Funktion an den Ort eingefügt, an dem sich der Teil befindet, und der vorherige Teil wird zuerst ausgeführt. Durch die Verwendung dieses Modifikators prüft die Funktion daher automatisch, ob der Nachrichtensender der Vertragsinhaber ist, und setzt sich dann wie gewohnt fort, wenn er wahr ist. Wenn nicht, wird es abstürzen.
Durch die Verwendung des einzigen Modifikators für Besitzer zu Funktionen, die die Gebühren und andere Parameter von Story DAO ändern, stellen wir sicher, dass nur Administratoren diese Änderungen vornehmen können.
Test
Testen wir die Anfangsfunktion.
Wenn es nicht vorhanden ist, erstellen Sie einen Ordnertest. Erstellen Sie dann die Dateien testStorydao.sol und testStoryDao.js. Da es keine native Methode gibt, um Ausnahmen zu testen, werden Helper/erwartungsstrow.js auch mit Folgendem erstellt:
export default async promise => { try { await promise; } catch (error) { const invalidOpcode = error.message.search('invalid opcode') >= 0; const outOfGas = error.message.search('out of gas') >= 0; const revert = error.message.search('revert') >= 0; assert( invalidOpcode || outOfGas || revert, 'Expected throw, got \'' + error + '\' instead', ); return; } assert.fail('Expected throw not received'); };
Hinweis: Soliditätstests werden normalerweise verwendet, um niedrige, vertragsbasierte Funktionen zu testen, dh die interne Struktur von intelligenten Verträgen. JS -Tests werden häufig verwendet, um zu testen, ob ein Vertrag von außen korrekt interagieren kann, was unsere Endbenutzer tun.
In testStoryDao.Sol den folgenden Inhalt einlegen:
pragma solidity ^0.4.24; import "../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol"; import "../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol"; contract StoryDao is Ownable { using SafeMath for uint256; mapping(address => bool) whitelist; uint256 public whitelistedNumber = 0; mapping(address => bool) blacklist; event Whitelisted(address addr, bool status); event Blacklisted(address addr, bool status); uint256 public daofee = 100; // 百分之几,即 100 为 1% uint256 public whitelistfee = 10000000000000000; // 以 Wei 为单位,这是 0.01 以太币 event SubmissionCommissionChanged(uint256 newFee); event WhitelistFeeChanged(uint256 newFee); uint256 public durationDays = 21; // 故事章节持续时间(天) uint256 public durationSubmissions = 1000; // 故事章节持续时间(条目) function changedaofee(uint256 _fee) onlyOwner external { require(_fee <= 1000); // 限制最大费用为 10% daofee = _fee; emit SubmissionCommissionChanged(_fee); } function changewhitelistfee(uint256 _fee) onlyOwner external { require(_fee > 0); // 确保费用大于 0 whitelistfee = _fee; emit WhitelistFeeChanged(_fee); } function changeDurationDays(uint256 _days) onlyOwner external { require(_days >= 1); durationDays = _days; } function changeDurationSubmissions(uint256 _subs) onlyOwner external { require(_subs > 99); durationSubmissions = _subs; } }
Dies wird überprüfen, ob der StoryDao -Vertrag mit den richtigen Gebühren und Dauerzahlen ordnungsgemäß eingesetzt wird. Die erste Zeile stellt sicher, dass sie durch das Lesen aus der bereitgestellten Adressliste bereitgestellt wird. Der letzte Abschnitt enthält einige Behauptungen - Überprüfen Sie, ob die Deklaration wahr oder falsch ist. In unserem Beispiel vergleichen wir die Nummer mit dem Anfangswert des implementierten Vertrags. Wann immer es "wahr" ist, wird der Abschnitt "Assert.Equals" ein Ereignis ausstellen, das "wahr" sagt, worauf Trüffel während des Tests hört.
In testStoryDao.js den folgenden Inhalt einlegen:
modifier onlyOwner() { require(msg.sender == owner); _; }
Damit unsere Tests erfolgreich ausgeführt werden können, müssen wir auch Trüffel erzählen, dass wir StoryDao bereitstellen möchten - weil es das für uns nicht tun wird. Erstellen wir also 3_Deploy_Storydao.js in der Migration mit fast dem gleichen Inhalt wie die Migration, die wir zuvor geschrieben haben:
export default async promise => { try { await promise; } catch (error) { const invalidOpcode = error.message.search('invalid opcode') >= 0; const outOfGas = error.message.search('out of gas') >= 0; const revert = error.message.search('revert') >= 0; assert( invalidOpcode || outOfGas || revert, 'Expected throw, got \'' + error + '\' instead', ); return; } assert.fail('Expected throw not received'); };
Zu diesem Zeitpunkt sollten wir auch die Paket.json -Datei im Root des Projektordners aktualisieren (oder, wenn nicht), mit den bisher benötigten Abhängigkeiten und dem, was wir in Zukunft benötigen, enthalten:
pragma solidity ^0.4.24; import "truffle/Assert.sol"; import "truffle/DeployedAddresses.sol"; import "../contracts/StoryDao.sol"; contract TestStoryDao { function testDeploymentIsFine() public { StoryDao sd = StoryDao(DeployedAddresses.StoryDao()); uint256 daofee = 100; // 百分之几,即 100 为 1% uint256 whitelistfee = 10000000000000000; // 以 Wei 为单位,这是 0.01 以太币 uint256 durationDays = 21; // 故事章节持续时间(天) uint256 durationSubmissions = 1000; // 故事章节持续时间(条目) Assert.equal(sd.daofee(), daofee, "初始 DAO 费用应为 100"); Assert.equal(sd.whitelistfee(), whitelistfee, "初始白名单费用应为 0.01 以太币"); Assert.equal(sd.durationDays(), durationDays, "初始天数持续时间应设置为 3 周"); Assert.equal(sd.durationSubmissions(), durationSubmissions, "初始提交持续时间应设置为 1000 个条目"); } }
und .babelRC -Dateien, die Folgendes enthalten:
import expectThrow from './helpers/expectThrow'; const StoryDao = artifacts.require("StoryDao"); contract('StoryDao Test', async (accounts) => { it("should make sure environment is OK by checking that the first 3 accounts have over 20 eth", async () =>{ assert.equal(web3.eth.getBalance(accounts[0]).toNumber() > 2e+19, true, "Account 0 has more than 20 eth"); assert.equal(web3.eth.getBalance(accounts[1]).toNumber() > 2e+19, true, "Account 1 has more than 20 eth"); assert.equal(web3.eth.getBalance(accounts[2]).toNumber() > 2e+19, true, "Account 2 has more than 20 eth"); }); it("should make the deployer the owner", async () => { let instance = await StoryDao.deployed(); assert.equal(await instance.owner(), accounts[0]); }); it("should let owner change fee and duration", async () => { let instance = await StoryDao.deployed(); let newDaoFee = 50; let newWhitelistFee = 1e+10; // 1 ether let newDayDuration = 42; let newSubsDuration = 1500; instance.changedaofee(newDaoFee, {from: accounts[0]}); instance.changewhitelistfee(newWhitelistFee, {from: accounts[0]}); instance.changeDurationDays(newDayDuration, {from: accounts[0]}); instance.changeDurationSubmissions(newSubsDuration, {from: accounts[0]}); assert.equal(await instance.daofee(), newDaoFee); assert.equal(await instance.whitelistfee(), newWhitelistFee); assert.equal(await instance.durationDays(), newDayDuration); assert.equal(await instance.durationSubmissions(), newSubsDuration); }); it("should forbid non-owners from changing fee and duration", async () => { let instance = await StoryDao.deployed(); let newDaoFee = 50; let newWhitelistFee = 1e+10; // 1 ether let newDayDuration = 42; let newSubsDuration = 1500; await expectThrow(instance.changedaofee(newDaoFee, {from: accounts[1]})); await expectThrow(instance.changewhitelistfee(newWhitelistFee, {from: accounts[1]})); await expectThrow(instance.changeDurationDays(newDayDuration, {from: accounts[1]})); await expectThrow(instance.changeDurationSubmissions(newSubsDuration, {from: accounts[1]})); }); it("should make sure the owner can only change fees and duration to valid values", async () =>{ let instance = await StoryDao.deployed(); let invalidDaoFee = 20000; let invalidDayDuration = 0; let invalidSubsDuration = 98; await expectThrow(instance.changedaofee(invalidDaoFee, {from: accounts[0]})); await expectThrow(instance.changeDurationDays(invalidDayDuration, {from: accounts[0]})); await expectThrow(instance.changeDurationSubmissions(invalidSubsDuration, {from: accounts[0]})); }) });
Wir müssen auch Babel in der Trüffelkonfiguration benötigen, damit es weiß, dass es beim Kompilieren von Tests verwendet werden sollte.
Hinweis: Babel ist ein Add-On zu NodeJs, mit dem wir das JavaScript der nächsten Generation in der aktuellen Generation von NodeJs verwenden können, damit wir Importe und andere Inhalte schreiben können. Wenn Sie das nicht verstehen, ignorieren Sie es einfach und fügen Sie es wörtlich ein. Nach der Installation müssen Sie sich möglicherweise nie wieder mit diesem Problem befassen.
var Migrations = artifacts.require("./Migrations.sol"); var StoryDao = artifacts.require("./StoryDao.sol"); module.exports = function(deployer, network, accounts) { if (network == "development") { deployer.deploy(StoryDao, {from: accounts[0]}); } else { deployer.deploy(StoryDao); } };
Führen Sie jetzt endlich Trüffel -Test aus. Die Ausgabe sollte dem ähnlich sein:
Weitere Informationen zum Testen finden Sie in diesem Tutorial, das wir speziell auf die Prüfung von intelligenten Verträgen vorbereitet haben.
Im nachfolgenden Abschnitt dieses Kurses werden wir die Tests überspringen, da das Eingeben von wörtlichem Tutorial das Tutorial zu lang macht. Weitere Informationen finden Sie jedoch auf den endgültigen Quellcode des Projekts, um alle Tests zu überprüfen. Der Prozess, den wir gerade abgeschlossen haben, hat eine Umgebung für die Tests eingerichtet, sodass Sie die Tests ohne weitere Einrichtung schreiben können.
Whitelist
Erstellen wir einen Whitelisting -Mechanismus, mit dem Benutzer am Erstellen von Geschichten teilnehmen können. Fügen Sie das folgende Funktionsframework zu StoryDao.Sol hinzu:
{ "name": "storydao", "devDependencies": { "babel-preset-es2015": "^6.18.0", "babel-preset-stage-2": "^6.24.1", "babel-preset-stage-3": "^6.17.0", "babel-polyfill": "^6.26.0", "babel-register": "^6.23.0", "dotenv": "^6.0.0", "truffle": "^4.1.12", "openzeppelin-solidity": "^1.10.0", "openzeppelin-solidity-metadata": "^1.2.0", "openzeppelin-zos": "", "truffle-wallet-provider": "^0.0.5", "ethereumjs-wallet": "^0.6.0", "web3": "^1.0.0-beta.34", "truffle-assertions": "^0.3.1" } }
Unbenannte Funktionsfunktion () wird als Fallback -Funktion bezeichnet, die aufgerufen wird, wenn Fonds an diesen Vertrag gesendet werden, aber keine spezifischen Anweisungen (d. H. Keine andere Funktion wird speziell aufgerufen). Dies ermöglicht es den Menschen, sich StoryDao anzuschließen, indem sie nur Äther nach Dao schicken und sofort an Whitelist kauft oder sofort anhand von Token gekauft wird, basierend darauf, ob sie whitelistet sind oder nicht.
Die Whitelistender -Funktion wird an Whitelist verwendet und kann direkt aufgerufen werden. Wir werden jedoch sicherstellen, dass die Fallback -Funktion sie automatisch nach dem Empfang etwas Äthers aufruft, sofern der Absender noch nicht weißeListet ist. Die Whitelistadaddress -Funktion wird öffentlich erklärt, da sie auch aus anderen Verträgen aufgerufen werden sollte, während die Fallback -Funktion extern ist, da die Mittel nur von externen Adressen an diese Adresse gesendet werden. Der Vertrag, der diesen Vertrag anruft, kann die erforderlichen Funktionen leicht direkt aufrufen.Lassen Sie uns zuerst mit der Fallback -Funktion umgehen.
pragma solidity ^0.4.24; import "../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol"; import "../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol"; contract StoryDao is Ownable { using SafeMath for uint256; mapping(address => bool) whitelist; uint256 public whitelistedNumber = 0; mapping(address => bool) blacklist; event Whitelisted(address addr, bool status); event Blacklisted(address addr, bool status); uint256 public daofee = 100; // 百分之几,即 100 为 1% uint256 public whitelistfee = 10000000000000000; // 以 Wei 为单位,这是 0.01 以太币 event SubmissionCommissionChanged(uint256 newFee); event WhitelistFeeChanged(uint256 newFee); uint256 public durationDays = 21; // 故事章节持续时间(天) uint256 public durationSubmissions = 1000; // 故事章节持续时间(条目) function changedaofee(uint256 _fee) onlyOwner external { require(_fee <= 1000); // 限制最大费用为 10% daofee = _fee; emit SubmissionCommissionChanged(_fee); } function changewhitelistfee(uint256 _fee) onlyOwner external { require(_fee > 0); // 确保费用大于 0 whitelistfee = _fee; emit WhitelistFeeChanged(_fee); } function changeDurationDays(uint256 _days) onlyOwner external { require(_days >= 1); durationDays = _days; } function changeDurationSubmissions(uint256 _subs) onlyOwner external { require(_subs > 99); durationSubmissions = _subs; } }Wir prüfen, ob der Absender noch nicht whitelistet ist, und delegiert den Anruf an die Whitelistadaddress -Funktion. Beachten Sie, dass wir die BuyTokens -Funktion kommentiert haben, weil wir sie noch nicht haben.
Als nächstes kümmern wir uns um die Whitelist.
modifier onlyOwner() { require(msg.sender == owner); _; }Beachten Sie, dass diese Funktion eine Adresse als Argument akzeptiert, anstatt sie aus einer Nachricht zu extrahieren (aus einer Transaktion). Dies hat den zusätzlichen Vorteil, dass sie in der Lage sind, die Whitelist andere zu ermöglichen, wenn es sich jemand nicht leisten kann, sich dem DAO anzuschließen.
Wir beginnen mit einigen Gesundheitscheckfunktionen: Der Absender muss whitelist oder schwarzlistet (verboten) werden und müssen genügend Gebühren gesendet haben, um sie zu bezahlen. Wenn diese Bedingungen zufriedenstellend sind, wird die Adresse dem Whitelist hinzugefügt, ein Whitelist -Ereignis wird ausgestellt. Wenn schließlich die Anzahl der gesendeten Ether größer ist als die Anzahl der zur Zahlung der Whitelist -Gebühr erforderlich, wird der Rest zum Kauf verwendet, um den Kauf zu kaufen. die Token.
Hinweis: Wir verwenden Sub anstelle von - um zu subtrahieren, da dies die Safemath -Funktion für sichere Berechnungen ist.
Solange Benutzer 0,01 Äther oder mehr Äther an den StoryDao -Vertrag senden, können sie sich jetzt selbst oder andere Whitelist selbst anwenden.
Schlussfolgerung
In diesem Tutorial haben wir den ersten Teil von DAO gebaut, aber es gibt noch viel zu tun. Bleiben Sie dran: Im nächsten Abschnitt werden wir uns mit dem Hinzufügen von Inhalten zur Geschichte befassen!FAQs zum Aufbau von Ethereum Dapps und Whitelists
Was sind die Voraussetzungen für den Bau eines Ethereum Dapp?
Bevor Sie mit dem Aufbau eines Ethereum -Dapps beginnen, müssen Sie ein grundlegendes Verständnis der Blockchain -Technologie, Ethereum und intelligenten Verträgen haben. Sie sollten auch mit Programmiersprachen wie JavaScript und Solidität vertraut sein, die zum Schreiben intelligenter Verträge über Ethereum verwendet werden. Darüber hinaus müssen Sie Tools wie Node.js, Trüffel, Ganache und Metamaske installieren, die für die Entwicklung und Prüfung von Dapps von entscheidender Bedeutung sind.
Wie funktioniert der Whitelisting -Prozess in DAPP?
Whitelisten sind Sicherheitsmaßnahmen in DAPPs, die den Zugriff auf bestimmte Merkmale oder Bereiche der Anwendung einschränken. Beim Erstellen einer Liste genehmigter Adressen, die die Interaktion mit DApps ermöglichen. Von diesen Adressen initiierten Transaktionen werden nur akzeptiert, während andere abgelehnt werden. Dies hilft, nicht autorisierten Zugang und böswillige Aktivitäten zu verhindern.
Welche Rolle spielen intelligente Verträge in Dapps?
Smart Contracts sind Selbstverträge, und ihre Vereinbarungsbedingungen werden direkt in den Code geschrieben. Sie spielen eine wichtige Rolle bei Dapps, da sie die Ausführung der Geschäftslogik in der Blockchain automatisieren. Sie gewährleisten Transparenz, Sicherheit und Unveränderlichkeit, da sie nach dem Einsatz nicht geändert oder manipuliert werden können.
Wie testet ich meinen Dapp?
Tests sind ein entscheidender Bestandteil der DAPP -Entwicklung, um seine Funktionalität und Sicherheit zu gewährleisten. Sie können Tools wie Trüffel und Ganache zum Testen verwenden. TRUFFL bietet Ethereum eine Entwicklungsumgebung, ein Testframework und eine Asset -Pipeline, während Sie mit Ganache eine private Ethereum -Blockchain zum Testen erstellen können.
Was ist DAO und wie hat es mit Dapp zu tun?
Dao repräsentiert eine dezentrale autonome Organisation. Es handelt sich um einen Organisationstyp, der durch Regeln dargestellt wird, die als Computerprogramme codiert werden, die transparent sind, von Organisationsmitgliedern kontrolliert und von der Zentralregierung nicht betroffen sind. Die Finanztransaktionen und -regeln von DAO werden auf der Blockchain aufbewahrt, was es zu einem Dapp macht.
Wie kann ich die Sicherheit meines Dapps gewährleisten?
Stellen Sie sicher, dass die Sicherheit des DAPP eine Vielzahl von Praktiken beinhaltet. Dies beinhaltet das Schreiben sicherer intelligenter Verträge, gründliche Tests, Durchführung von Sicherheitsaudits und das Aufbewahren von Software und Abhängigkeiten auf dem neuesten Stand. Es ist auch wichtig, Best Practices für sichere Codierung zu befolgen und über die neuesten Sicherheitslücken und Bedrohungen im Blockchain -Bereich auf dem Laufenden zu bleiben.
Was ist Metamask und warum ist es wichtig für die DAPP -Entwicklung?
Metamask ist eine Browser -Erweiterung, mit der Sie mit der Ethereum -Blockchain und Dapps direkt von Ihrem Browser interagieren können. Es kann auch als Ethereum-Brieftasche dienen, um Ihre Ethereum- und ERC-20-Token zu verwalten. Es ist wichtig bei der DAPP-Entwicklung, da es Benutzern eine benutzerfreundliche Oberfläche bietet, damit Benutzer mit Ihrem DApp interagieren können, ohne einen vollständigen Ethereum-Knoten auszuführen.
Wie bereitet ich meinen Dapp bereit?
Sobald Sie Ihren DAPP entwickelt und getestet haben, können Sie ihn für das Ethereum Mainnet oder das TestNet bereitstellen. Dies beinhaltet das Zusammenstellen Ihrer intelligenten Verträge, die Bereitstellung von Blockchain und die Verbindung Ihrer DAPPs mit diesen Verträgen. Sie können diesen Vorgang mithilfe von Tools wie TRUFFL und Infura abschließen.
Was sind die Herausforderungen der DAPP -Entwicklung?
DAPP -Entwicklung steht vor einigen Herausforderungen. Dies beinhaltet den Umgang mit Skalierbarkeitsproblemen des Ethereum-Netzwerks, der Gewährleistung der Sicherheit von DApps, der Verwaltung der volatilen Gaspreise für Transaktionen und der Bereitstellung einer benutzerfreundlichen Schnittstelle. Es erfordert auch ein Auge auf sich schnell entwickelnde Blockchain -Technologien und -vorschriften.
Wie aktualisiere ich meinen DAPP nach der Bereitstellung?
Die Aktualisierung von DApps nach der Bereitstellung kann eine Herausforderung sein, da intelligente Verträge auf der Blockchain unveränderlich sind. Sie können jedoch aufgerüstbare Verträge entwerfen, indem Sie Daten und Logik in verschiedene Verträge oder Aufrüstungsverträge mithilfe delegierter Anrufe trennen. Die Planung für Upgrades und Änderungen während der Entwurfsphase des DAPP ist sehr wichtig.
Das obige ist der detaillierte Inhalt vonBauen von Ethereum Dapps: Whitelisting & Testen einer Geschichte DAO. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Die kundenspezifische Entwicklung von Telekommunikationssoftware ist zweifellos eine beträchtliche Investition. Langfristig können Sie jedoch erkennen, dass ein solches Projekt möglicherweise kostengünstiger ist, da es Ihre Produktivität wie jede fertige Lösung auf dem Markt steigern kann. Verstehen Sie die wichtigsten Vorteile des Aufbaus eines maßgeschneiderten Telekommunikationssystems. Holen Sie sich die genauen Funktionen, die Sie benötigen Es gibt zwei potenzielle Probleme mit der von Ihnen gekauften Telekommunikationssoftware. Einige fehlen nützliche Funktionen, die Ihre Produktivität erheblich verbessern können. Manchmal können Sie sie mit einer externen Integration verbessern, aber das ist nicht immer genug, um sie großartig zu machen. Andere Software hat zu viele Funktionen und ist zu kompliziert, um sie zu verwenden. Sie werden wahrscheinlich einige davon nicht verwenden (niemals!). Eine große Anzahl von Funktionen trägt normalerweise zum Preis bei. Basierend auf Ihren Bedürfnissen

CI/CD -Rätsel und -Lösungen für Open -Source -Software in ARM64 Architektur Die Bereitstellung von Open -Source -Software auf der ARM64 -Architektur erfordert eine leistungsstarke CI/CD -Umgebung. Es gibt jedoch einen Unterschied zwischen den Stützniveaus von ARM64 und herkömmlichen X86 -Prozessorarchitekturen, die häufig im Nachteil sind. Infrastrukturkomponentenentwickler für mehrere Architekturen haben bestimmte Erwartungen für ihr Arbeitsumfeld: Konsistenz: Die Tools und Methoden, die über Plattformen hinweg verwendet werden, sind konsistent und vermeiden, dass der Entwicklungsprozess aufgrund der Einführung weniger beliebter Plattformen geändert werden muss. Leistung: Die Plattform- und Support -Mechanismus haben eine gute Leistung, um sicherzustellen, dass die Bereitstellungsszenarien bei der Unterstützung mehrerer Plattformen nicht von unzureichender Geschwindigkeit beeinflusst werden. Testabdeckung: Effizienz, Konformität und

Bleiben Sie über die neuesten technischen Trends mit diesen Top -Entwickler -Newsletters informiert! Diese kuratierte Liste bietet für jeden etwas, von KI -Enthusiasten bis hin zu erfahrenen Backend- und Frontend -Entwicklern. Wählen Sie Ihre Favoriten und sparen Sie Zeit, um nach REL zu suchen

Dieses Tutorial führt Sie durch das Erstellen einer serverlosen Bildverarbeitungspipeline mit AWS -Diensten. Wir werden ein Next.JS -Frontend erstellen, der in einem ECS -Fargate -Cluster eingesetzt wird und mit einem API -Gateway, Lambda -Funktionen, S3 -Eimer und DynamoDB interagiert. Th

Dieses Pilotprogramm, eine Zusammenarbeit zwischen CNCF (Cloud Native Computing Foundation), Ampere Computing, Equinix Metal und betätigten, rationalisiert ARM64 CI/CD für CNCF -Github -Projekte. Die Initiative befasst sich mit Sicherheitsbedenken und Leistung


Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heißer Artikel

Heiße Werkzeuge

Sicherer Prüfungsbrowser
Safe Exam Browser ist eine sichere Browserumgebung für die sichere Teilnahme an Online-Prüfungen. Diese Software verwandelt jeden Computer in einen sicheren Arbeitsplatz. Es kontrolliert den Zugriff auf alle Dienstprogramme und verhindert, dass Schüler nicht autorisierte Ressourcen nutzen.

ZendStudio 13.5.1 Mac
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

VSCode Windows 64-Bit-Download
Ein kostenloser und leistungsstarker IDE-Editor von Microsoft

MinGW – Minimalistisches GNU für Windows
Dieses Projekt wird derzeit auf osdn.net/projects/mingw migriert. Sie können uns dort weiterhin folgen. MinGW: Eine native Windows-Portierung der GNU Compiler Collection (GCC), frei verteilbare Importbibliotheken und Header-Dateien zum Erstellen nativer Windows-Anwendungen, einschließlich Erweiterungen der MSVC-Laufzeit zur Unterstützung der C99-Funktionalität. Die gesamte MinGW-Software kann auf 64-Bit-Windows-Plattformen ausgeführt werden.
